Predicción de Series de Tiempo#
Ejercicio 1.#
Considere la serie de tiempo asociada con los futuros de la criptomoneda Bitcoin desde que comenzó a comercializarse hasta la fecha del día de hoy. Utilice la API de Yahoo Finance para obtener esta serie de tiempo.
from datetime import datetime, timedelta
import datetime as dt
import seaborn as sns
import matplotlib.pyplot as plt
import plotly.graph_objects as go
import psycopg2
import pandas as pd
import kaleido
import numpy as np
from scipy.stats import kstest
import statsmodels.api as sm
import scipy.stats as stats
import statsmodels.graphics.tsaplots as tsaplots
import yfinance as yf
data = yf.Ticker("BTC-USD")
data.info
{'name': 'Bitcoin',
'startDate': 1278979200,
'description': 'Bitcoin (BTC) is a cryptocurrency launched in 2010. Users are able to generate BTC through the process of mining. Bitcoin has a current supply of 19,685,875. The last known price of Bitcoin is 61,540.45487545 USD and is down -2.87 over the last 24 hours. It is currently trading on 11013 active market(s) with $42,618,670,077.96 traded over the last 24 hours. More information can be found at https://bitcoin.org/.',
'maxAge': 86400,
'priceHint': 2,
'previousClose': 61281.86,
'open': 61281.86,
'dayLow': 60918.156,
'dayHigh': 64120.5,
'regularMarketPreviousClose': 61281.86,
'regularMarketOpen': 61281.86,
'regularMarketDayLow': 60918.156,
'regularMarketDayHigh': 64120.5,
'volume': 36111052800,
'regularMarketVolume': 36111052800,
'averageVolume': 35492800004,
'averageVolume10days': 41660236821,
'averageDailyVolume10Day': 41660236821,
'marketCap': 1250881306624,
'fiftyTwoWeekLow': 24797.168,
'fiftyTwoWeekHigh': 73750.07,
'fiftyDayAverage': 67298.07,
'twoHundredDayAverage': 46786.8,
'currency': 'USD',
'fromCurrency': 'BTC',
'toCurrency': 'USD=X',
'lastMarket': 'CoinMarketCap',
'coinMarketCapLink': 'https://coinmarketcap.com/currencies/bitcoin',
'volume24Hr': 36111052800,
'volumeAllCurrencies': 36111052800,
'circulatingSupply': 19686462,
'exchange': 'CCC',
'quoteType': 'CRYPTOCURRENCY',
'symbol': 'BTC-USD',
'underlyingSymbol': 'BTC-USD',
'shortName': 'Bitcoin USD',
'longName': 'Bitcoin USD',
'firstTradeDateEpochUtc': 1410912000,
'timeZoneFullName': 'UTC',
'timeZoneShortName': 'UTC',
'uuid': '74397779-1589-3270-8c45-b7f1a7345b3a',
'messageBoardId': 'finmb_BTC_CCC',
'trailingPegRatio': None}
sns.set_theme() #para configurar el tema a usar en las figuras
sns.set_context("paper")
#Defición de parámetros para indexación de datos en BTC_df_sorted
stock = 'BTC-USD'
resolution = '1d'
#indexación de datos en BTC_df_sorted
BTC_df= yf.download("BTC-USD", interval=resolution)
BTC_df_sorted = BTC_df.sort_values(by='Date', ascending=True)
BTC_df_sorted.reset_index(inplace=True)
BTC_df_sorted.head()
[*********************100%%**********************] 1 of 1 completed
| Date | Open | High | Low | Close | Adj Close | Volume | |
|---|---|---|---|---|---|---|---|
| 0 | 2014-09-17 | 465.864014 | 468.174011 | 452.421997 | 457.334015 | 457.334015 | 21056800 |
| 1 | 2014-09-18 | 456.859985 | 456.859985 | 413.104004 | 424.440002 | 424.440002 | 34483200 |
| 2 | 2014-09-19 | 424.102997 | 427.834991 | 384.532013 | 394.795990 | 394.795990 | 37919700 |
| 3 | 2014-09-20 | 394.673004 | 423.295990 | 389.882996 | 408.903992 | 408.903992 | 36863600 |
| 4 | 2014-09-21 | 408.084991 | 412.425995 | 393.181000 | 398.821014 | 398.821014 | 26580100 |
Detección de valores atípicos (outliers):
A continuación, se realiza un análisis para identificar la presencia de outliers en nuestro conjunto de datos. Para esto usamos el método de detección de valores atípicos mediante las puntuaciones \( Z \), el cual establece el siguiente criterio: Cualquier dato cuya puntuación esté fuera de la tercera desviación estándar es un valor atípico.
La función outliers_zscore recorrer todos los datos y calcular la puntuación \( Z \) para cada punto de datos utilizando la fórmula \( \frac{(x_i - \mu)}{\sigma} \), donde \( x_i \) es cada valor de los datos, \( \mu \) es la media de los datos y \( \sigma \) es la desviación estándar de los datos. Luego, establece un umbral en la tercera desviación estandar e identifica como valores atípicos aquellos datos cuya puntuación \( Z \) (en valor absoluto) excede este umbral.
from IPython.display import display, Markdown
display(Markdown('<center><img src="img/outlierszscore.png" alt="figure"></center>'))

import numpy as np
#Definición de función para detección de datos atípicos a través de ZScore
def outliers_zscore(data):
outliers = []
thres = 3
mean = np.mean(data)
std = np.std(data)
for i in data:
z_score = (i - mean)/std
if (np.abs(z_score) > thres):
outliers.append(i)
return outliers
A continuación, se observan los datos atípicos obtenidos luego de aplicar el método descrito anteriormente.
BTC_df_outliers= BTC_df_sorted[["Close"]]
Close_outliers = outliers_zscore(BTC_df_outliers.Close)
outliers_df = pd.DataFrame({"Close_Outlieres": Close_outliers})
print("A continuación se imprimen Outliers a través Método Z-scores para el precio de Cierre del Bitcoin: ")
print(outliers_df)
A continuación se imprimen Outliers a través Método Z-scores para el precio de Cierre del Bitcoin:
Close_Outlieres
0 69019.789062
1 72123.906250
2 71481.289062
3 73083.500000
4 71396.593750
5 69403.773438
6 69958.812500
7 69987.835938
8 69455.343750
9 70744.953125
10 69892.828125
11 69645.304688
12 71333.648438
13 69702.148438
14 68896.109375
15 69362.554688
16 71631.359375
17 69139.015625
18 70587.882812
19 70060.609375
Basándonos en los resultados del Método Z-Scores, se confirma la presencia de valores atípicos en nuestro conjunto de datos. No obstante, optamos por no eliminarlos ni aplicar técnicas de imputación, ya que el número de valores atípicos no es significativo en relación con el tamaño total del conjunto de datos.
Gráfico de candlestick de datos de Bitcoin (BTC-USD).
import plotly.graph_objects as go
import plotly.io as pio
import plotly.offline as py
df_g = BTC_df_sorted.copy()
fig = go.Figure(data=[go.Candlestick(x = df_g['Date'],
open = df_g['Open'],
high = df_g['High'],
low = df_g['Low'],
close = df_g['Close'],
increasing_line_color='#008080', # Color de línea de velas alcistas
decreasing_line_color='#B22222', # Color de línea de velas bajistas
increasing_fillcolor='#B0E0E6', # Color de relleno de velas alcistas
decreasing_fillcolor='#DB7093' # Color de relleno de velas bajistas)
)
]
)
fig.update_layout(
title="Bitcoin USD (BTC-USD)",
xaxis_title="Day",
yaxis_title="BTC-USD",
font=dict(
family="Verdana, monospace",
size=12,
)
)
fig.update_layout(xaxis_rangeslider_visible=False)
fig.show()
El gráfico de velas (candlestick) representa la evolución del precio de la criptomoneda Bitcoin desde el 17 de Septiembre de 2014 a la fecha, mostrando datos diarios. En este gráfico cada vela representa un día de trading:
Si el precio de apertura es mayor que el precio de cierre para ese día, la vela se dibuja de color azul, la cola superior de la vela representa el precio máximo alcanzado durante el día y la cola inferior de la vela representa el precio mínimo alcanzado durante el día.
Si el precio de cierre es mayor que el precio de apertura para ese día, la vela se dibuja de color rojo. De igual forma la cola superior de la vela representa el precio máximo alcanzado durante el día y la cola inferior de la vela representa el precio mínimo alcanzado durante el día.
En resumen, el gráfico de candlestick ofrece una representación visual de la variación diaria del precio de Bitcoin durante el periodo mencionado, mostrando tanto los rangos de precio máximo y mínimo como la relación entre el precio de apertura y el precio de cierre de cada día.
Serie de tiempo Bitcoin (BTC-UDS).
BTC_data = BTC_df_sorted.copy()
# Configurar estilo de seaborn y establecer el fondo en blanco
sns.set_style("whitegrid")
#Gráfico
sns.lineplot(data=BTC_data, x='Date', y='Close', color='#008080')
# Personalizar etiquetas de los ejes y título del gráfico
plt.xlabel("Fecha", fontsize=10) # Establecer etiqueta del eje x
plt.ylabel("Precio de Cierre (USD)", fontsize=10) # Establecer etiqueta del eje y
plt.title("Precio de cierre de Bitcoin a lo largo del tiempo", fontsize=12) # Establecer título del gráfico
Text(0.5, 1.0, 'Precio de cierre de Bitcoin a lo largo del tiempo')
El gráfico ilustra la evolución del precio de Bitcoin desde el 17 de septiembre de 2014 hasta la fecha actual. Durante este período, el precio se mantuvo relativamente estable hasta 2017, momento en el que experimentó un notable aumento. En 2021, hubo un nuevo y significativo incremento, seguido de un declive en 2022. Sin embargo, en 2023 se observa una recuperación y el precio continúa mostrando una tendencia alcista. Dado este comportamiento ascendente a lo largo del tiempo, podemos concluir que el gráfico representa la evolución del precio de Bitcoin. Además, la serie de tiempo correspondiente se caracteriza como no estacionaria.
Una serie de tiempo se considera No estacionaria si la distribución de sus datos (media, varianza, autocorrelación, etc.) no permanece constante a lo largo del tiempo, es decir, si muestra tendencia, variación en la varianza, autocorrelación significativa.
Ejercicio 2.#
Repita TODOS los pasos indicados en esta sección para encontrar modelos ARIMA para predecir el precio de Bitcoin con los siguientes horizontes: 7, 14, 21 y 28 días. Utilizar siempre predicciones usando rolling con ventana de predicción continua de un día. Cualquier cantidad de pasos extra para enriquecer su análisis predictivo serán aceptados siempre y cuando sean acordes con lo que indica la teoría de análisis de series de tiempo.
from IPython.display import display, Markdown
display(Markdown('<center><img src="img/ejercicio2.png" alt="figure"></center>'))

¿La serie de tiempo es estacionaria o no es estacionaria?#
Primeramente, verificaremos si la serie de tiempo es NO estacionaria. Para esto usamos la prueba de Dickey-Fuller, ya que, para aplicar un modelo ARIMA nuestra serie de tiempo debe ser estacionaria. Para esto, procedemos con la instalación de la libreria statemodels a través del siguiente comando:
pip install statsmodels.
from statsmodels.tsa.stattools import adfuller
from numpy import log
Planteamiento de Hipótesis:
Críterios de aceptación y/o rechazo:
Sí el P-value \(< 0.05 \), se rechaza la hipótesis nula con un a significancia \( \alpha = 0.05\), es decir que la serie de tiempo es estacionaria.
result = adfuller(BTC_df_sorted.Close)
print('ADF Statistic: %f' % result[0])
print('p-value: %f' % result[1])
ADF Statistic: -0.812080
p-value: 0.815548
De acuerdo al resultado obtenido con la prueba de Dickey-Fuller con P-value \(= 0,8189 > 0,05\), por tanto se rechaza la hipótesis alternativa con una significancia \(\alpha = 0.05\), es decir que la serie de tiempo es NO estacionaria.
A continuación gráficamos la Autocorrelación y estacionalidad de la serie de tiempo asociada con los futuros de la criptomoneda Bitcoin (BTC-USD).
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf
from statsmodels.tsa.stattools import acf
import pandas as pd
fig, axes = plt.subplots(nrows=1, ncols=2, sharex=True,figsize=(18,6))
axes[0].plot(BTC_df_sorted.Close, color ='#008080')
axes[0].set_title('Original Series', fontsize=16)
axes[0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
figtest0=plot_acf(BTC_df_sorted.Close, ax=axes[1], lags = 240, color = '#008080', vlines_kwargs ={"colors":'#008080'})
axes[1].set_title('Autocorrelation', fontsize=16)
axes[1].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
Gráfico Original Series: El gráfico representa el comportamiento del precio de la criptomoneda Bitcoin en un periodo de tiempo. Al tener un comportamiento acendente en el tiempo, se puede afirmar que representa la evolución del precio del Bitcoin a lo largo del tiempo.
Gráfico Autocorrelation Original Series: Como se puede observar en gráfico ACF, la autocorrelación de la serie con sus rezagos decae lentamente en el tiempo de forma lineal; ésto es coherente con el resultado obtenido luego de aplicar la prueba de
Dickey-Fuller.
Eliminación de la tendencia entre la serie y sus rezagos.#
La eliminación de la tendencia y de la correlación entre la serie y sus rezagos puede hacerse por diferenciación.
Diferenciación de 1er Orden:#
fig, axes = plt.subplots(nrows=1, ncols=2, sharex=True,figsize=(18,6))
axes[0].plot(BTC_df_sorted.Close.diff(), color ='#008080');
axes[0].set_title('1st Order Differencing', fontsize=16)
axes[0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
figtest1=plot_acf(BTC_df_sorted.Close.diff().dropna(), ax=axes[1], lags = 240, color = '#008080', vlines_kwargs ={"colors":'#008080'})
axes[1].set_title('Autocorrelation', fontsize=16)
axes[1].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
Luego de aplicar una diferenciación de 1er orden, procedemos aplicar nuevamente la prueba de Dickey-Fuller para validar si nuestra serie de tiempo es estacionaria.
from statsmodels.tsa.stattools import adfuller
from numpy import log
result1 = adfuller(BTC_df_sorted.Close.diff().dropna())
print('ADF Statistic: %f' % result1[0])
print('p-value: %f' % result1[1])
ADF Statistic: -8.800824
p-value: 0.000000
De acuerdo al resultado obtenido con la prueba de Dickey-Fuller con P-value \(<0.000000\), por tanto no se rechaza la hipótesis nula con una significancia \(\alpha = 0.05\), es decir que la serie de tiempo es estacionaria.
Diferenciación de 2do Orden:#
fig, axes = plt.subplots(nrows=1, ncols=2, sharex=True,figsize=(18,6))
axes[0].plot(BTC_df_sorted.Close.diff().diff(), color ='#008080')
axes[0].set_title('2do Order Differencing',fontsize=16)
axes[0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
figtest2=plot_acf(BTC_df_sorted.Close.diff().diff().dropna(), ax=axes[1], lags = 240, color = '#008080', vlines_kwargs ={"colors":'#008080'})
axes[1].set_title('Autocorrelation', fontsize=16)
axes[1].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
Luego de aplicar una diferenciación de 2do orden, procedemos aplicar nuevamente la prueba de Dickey-Fuller para validar si nuestra serie de tiempo continua siendo estacionaria.
from statsmodels.tsa.stattools import adfuller
from numpy import log
result2 = adfuller(BTC_df_sorted.Close.diff().diff().dropna())
print('ADF Statistic: %f' % result2[0])
print('p-value: %f' % result2[1])
ADF Statistic: -19.899003
p-value: 0.000000
De acuerdo al resultado obtenido con la prueba de Dickey-Fuller con P-value \(<0.00000\), por tanto no se rechaza la hipótesis nula con una significancia \(\alpha = 0.05\), es decir que la serie de tiempo es no estacionaria. Sin embargo al momento de análizar el gráfico de autocorrelación para la 2da diferenciación, el retraso entra en el zona negativa muy distante de nuestro limite de tolerancia, lo que indica que la serie podría haber sido sobrediferenciada.
Por lo tanto, vamos a fijar el orden de diferenciación como 1, es decir, \( d = 1\) .
Construcción de modelo ARIMA para predecir el precio de Bitcoin con los siguientes horizontes: 7, 14, 21 y 28#
Función de Ajuste del modelo y predicciones ARIMA#
from statsmodels.tsa.arima.model import ARIMA
import warnings
warnings.filterwarnings("ignore") # suprimir advertencias durante el ajuste del modelo.
def arima_model_fit(data_df):
# Realiza predicciones continuas usando un enfoque de desplazamiento
# y almacena las predicciones en una lista
data = data_df.copy()
n_BTC = len(data.Close)
train_size = n_BTC - 28 # Tamaño del conjunto de entrenamiento - 28 días
train = data.Close[:train_size] # Datos de entrenamiento (precios de cierre)
dates_train = data.Date[:train_size] # Fechas correspondientes a los datos de entrenamiento
#A través de la siguiente función que depende sólo del input `train` y retornarán los parámetros `p`, `d`, `q` y que definiendo el mejor modelo ARIMA con el menor criterio `AIC` de bondad de ajuste.
#**Nota:** Consideramos el `método: mle`para el cálculo de verosimilitud a través del filtro de Kalman.
best_aic = np.inf
best_bic = np.inf
best_order = None
best_mdl = None
pq_rng = range(3)
d_rng = range(2)
for p in pq_rng:
for d in d_rng:
for q in pq_rng:
try:
# print(i, d, j)
tmp_mdl = ARIMA(train, order=(p,d,q)).fit()
tmp_aic = tmp_mdl.aic
if tmp_aic < best_aic:
best_aic = tmp_aic
best_order = (p, d, q)
best_mdl = tmp_mdl
except: continue
print('Best AIC:', best_aic)
print('Best Order:', best_order)
print('aic: {:6.5f} | order: {}'.format(best_aic, best_order))
model = ARIMA(train, order=best_order)
model_fit = model.fit()
return model_fit, train, dates_train, best_order
Función Rolling forecast#
def arima_rolling(history, test, best_order): # arima_rolling(train.tolist(), test_nd, best_order)
predictions = list()
for t in range(len(test)):
model = ARIMA(history, order=best_order)
model_fit = model.fit()
output = model_fit.forecast()
yhat = output[0]
predictions.append(yhat)
obs = test[t]
history.append(obs)
print('predicted=%f, expected=%f' % (yhat, obs))
return predictions
Indexación de parámetros para la función arima_model_fit()#
La siguiente función devuelve los parámetros p, d, q que definen el mejor modelo ARIMA con el menor criterio AIC (Criterio de Información de Akaike) de bondad de ajuste. Además, proporciona los resultados del modelo ARIMA ajustado para datos de entrenamiento, incluyendo las fechas correspondientes. También incluye los datos y fechas del modelo ARIMA de prueba, aunque estos últimos dos no son directamente visibles en la salida de la función.
model_fit,train,dates_train,best_order = arima_model_fit(BTC_df_sorted)
Best AIC: 56472.04159778856
Best Order: (2, 1, 2)
aic: 56472.04160 | order: (2, 1, 2)
Según el criterio de AIC, se determinó que el modelo ARIMA óptimo es (2,1,2).
Nota: La función auto_arima de Python es útil en ciertos casos específicos. Sin embargo, este no es uno de ellos, ya que el modelo ARIMA que proporciona es simplemente un random walk. Este tipo de modelo predice puramente como un modelo estocástico con dependencia temporal basada únicamente en el punto temporal anterior. Los datos financieros, especialmente los precios de activos como el Bitcoin, suelen ser muy volátiles y pueden mostrar comportamientos no lineales o estacionarios cambiantes en el tiempo. Esto puede dificultar que un modelo auto_arima capture la complejidad de los datos y construya el mejor modelo. Por esta razón, no utilizaremos esta función.
Indexación de parámetros para la función arima_rolling()#
La siguiente función devuelve las prediciones, con base a los parámetros p, d, q que definen el mejor modelo ARIMA con el menor criterio AIC (Criterio de Información de Akaike) de bondad de ajuste, aprovechando datos históricos para pronosticar continuamente el precio futuro del Bitcoin durante un período (horizonte) específico.
Horizonte de 7 días
train_size = len(BTC_df_sorted.Close) - 28
test_7 = BTC_df_sorted.Close[train_size:train_size + 7]
dates_7 = BTC_df_sorted.Date[train_size:train_size + 7]
test_7l = test_7.tolist()
train_7l = train.tolist()
yhat_7 = arima_rolling(train_7l, test_7l, best_order)
predicted=65458.494464, expected=63778.761719
predicted=63860.747030, expected=64062.203125
predicted=64096.574807, expected=67234.171875
predicted=67062.720436, expected=69958.812500
predicted=69768.273352, expected=69987.835938
predicted=70002.110586, expected=69455.343750
predicted=69664.323396, expected=70744.953125
Horizonte de 14 días
train_size = len(BTC_df_sorted.Close) - 28
test_14 = BTC_df_sorted.Close[train_size:train_size + 14]
dates_14 = BTC_df_sorted.Date[train_size:train_size + 14]
test_14l = test_14.tolist()
train_14l = train.tolist()
yhat_14 = arima_rolling(train_14l, test_14l, best_order)
predicted=65458.494464, expected=63778.761719
predicted=63860.747030, expected=64062.203125
predicted=64096.574807, expected=67234.171875
predicted=67062.720436, expected=69958.812500
predicted=69768.273352, expected=69987.835938
predicted=70002.110586, expected=69455.343750
predicted=69664.323396, expected=70744.953125
predicted=70861.279487, expected=69892.828125
predicted=69812.695365, expected=69645.304688
predicted=69475.677678, expected=71333.648438
predicted=71183.721412, expected=69702.148438
predicted=69815.816683, expected=65446.972656
predicted=65828.220564, expected=65980.812500
predicted=66086.075423, expected=68508.843750
Horizonte de 21 días
train_size = len(BTC_df_sorted.Close) - 28
test_21 = BTC_df_sorted.Close[train_size:train_size + 21]
dates_21 = BTC_df_sorted.Date[train_size:train_size + 21]
test_21l = test_21.tolist()
train_21l = train.tolist()
yhat_21 = arima_rolling(train_21l, test_21l, best_order)
predicted=65458.494464, expected=63778.761719
predicted=63860.747030, expected=64062.203125
predicted=64096.574807, expected=67234.171875
predicted=67062.720436, expected=69958.812500
predicted=69768.273352, expected=69987.835938
predicted=70002.110586, expected=69455.343750
predicted=69664.323396, expected=70744.953125
predicted=70861.279487, expected=69892.828125
predicted=69812.695365, expected=69645.304688
predicted=69475.677678, expected=71333.648438
predicted=71183.721412, expected=69702.148438
predicted=69815.816683, expected=65446.972656
predicted=65828.220564, expected=65980.812500
predicted=66086.075423, expected=68508.843750
predicted=68210.458405, expected=67837.640625
predicted=67719.156050, expected=68896.109375
predicted=68881.661974, expected=69362.554688
predicted=69468.841935, expected=71631.359375
predicted=71671.930041, expected=69139.015625
predicted=69355.259998, expected=70587.882812
predicted=70566.796147, expected=70060.609375
Horizonte de 28 días
train_size = len(BTC_df_sorted.Close) - 28
test_28 = BTC_df_sorted.Close[train_size:train_size + 28]
dates_28 = BTC_df_sorted.Date[train_size:train_size + 28]
test_28l = test_28.tolist()
train_28l = train.tolist()
yhat_28 = arima_rolling(train_28l, test_28l, best_order)
predicted=65458.494464, expected=63778.761719
predicted=63860.747030, expected=64062.203125
predicted=64096.574807, expected=67234.171875
predicted=67062.720436, expected=69958.812500
predicted=69768.273352, expected=69987.835938
predicted=70002.110586, expected=69455.343750
predicted=69664.323396, expected=70744.953125
predicted=70861.279487, expected=69892.828125
predicted=69812.695365, expected=69645.304688
predicted=69475.677678, expected=71333.648438
predicted=71183.721412, expected=69702.148438
predicted=69815.816683, expected=65446.972656
predicted=65828.220564, expected=65980.812500
predicted=66086.075423, expected=68508.843750
predicted=68210.458405, expected=67837.640625
predicted=67719.156050, expected=68896.109375
Gráfica lineplot modelo ARIMA_rolling para predecir el precio de Bitcoin con un horizonte de 7, 14, 21 y 28 días#
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
#Gráfica horizonte 7 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[0], color='#009900', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_7, y=test_7, ax=axes[0], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=yhat_7, ax=axes[0], label='Forecast', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[0].set_xlabel(None)
axes[0].legend(fontsize=14) # Mostrar la leyenda
axes[0].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 14 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[1], color='#009900', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_14, y=test_14, ax=axes[1], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=yhat_14, ax=axes[1], label='Forecast', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[1].set_xlabel(None)
axes[1].legend(fontsize=14) # Mostrar la leyenda
axes[1].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 21 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[2], color='#009900', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_21, y=test_21, ax=axes[2], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=yhat_21, ax=axes[2], label='Forecast', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[2].set_xlabel(None)
axes[2].legend(fontsize=14) # Mostrar la leyenda
axes[2].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[2].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 28 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[3], color='#009900', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_28, y=test_28, ax=axes[3], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=yhat_28, ax=axes[3], label='Forecast', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[3].set_xlabel('Fecha', fontsize=12)
axes[3].legend(fontsize=14) # Mostrar la leyenda
axes[3].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[3].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
plt.show()
En el gráfico anterior se presentan las predicciones para horizontes de 7, 14, 21 y 28 días. La línea verde representa los datos utilizados para entrenar el modelo ARIMA. La línea azul muestra los datos reales u observaciones correspondientes a cada horizonte, mientras que la línea punteada indica las predicciones generadas por nuestro modelo ARIMA a partir de los datos de entrenamiento. Estas predicciones se comparan con los valores reales de prueba para evaluar la precisión del modelo.
También se aprecia un sesgo entre los datos reales de prueba y las predicciones proporcionadas por nuestro modelo ARIMA, basadas en los datos de entrenamiento.
Ejercicio 3.#
Repita el paso 2 ahora sin utilizar rolling. Esto es, realice el pronóstico solo utilizando forecast() para los diferentes horizontes de predicción, 7, 14, 21 y 28 días.
A continuación se ajusta nuestro modelo ARIMA utilizando forecast() para los diferentes horizontes de predicción, 7, 14, 21 y 28 días, y así poder visualizar las predicciones del precio de cierre de la criptomoneda Bitcoin.
Horizonte de 7 días
predic_forecast7 = model_fit.forecast(7)
print(predic_forecast7)
3474 65458.494464
3475 65469.217327
3476 65506.959254
3477 65528.716848
3478 65513.547322
3479 65481.913168
3480 65469.104822
Name: predicted_mean, dtype: float64
Horizonte de 14 días
predic_forecast14 = model_fit.forecast(14)
print(predic_forecast14)
3474 65458.494464
3475 65469.217327
3476 65506.959254
3477 65528.716848
3478 65513.547322
3479 65481.913168
3480 65469.104822
3481 65486.302922
3482 65511.754461
3483 65517.675011
3484 65500.216718
3485 65480.598282
3486 65479.724074
3487 65496.228503
Name: predicted_mean, dtype: float64
Horizonte de 21 días
predic_forecast21 = model_fit.forecast(21)
print(predic_forecast21)
3474 65458.494464
3475 65469.217327
3476 65506.959254
3477 65528.716848
3478 65513.547322
3479 65481.913168
3480 65469.104822
3481 65486.302922
3482 65511.754461
3483 65517.675011
3484 65500.216718
3485 65480.598282
3486 65479.724074
3487 65496.228503
3488 65510.628019
3489 65508.029204
3490 65493.238830
3491 65483.304624
3492 65488.086505
3493 65500.759109
3494 65507.027237
Name: predicted_mean, dtype: float64
Horizonte de 28 días
predic_forecast28 = model_fit.forecast(28)
print(predic_forecast28)
3474 65458.494464
3475 65469.217327
3476 65506.959254
3477 65528.716848
3478 65513.547322
3479 65481.913168
3480 65469.104822
3481 65486.302922
3482 65511.754461
3483 65517.675011
3484 65500.216718
3485 65480.598282
3486 65479.724074
3487 65496.228503
3488 65510.628019
3489 65508.029204
3490 65493.238830
3491 65483.304624
3492 65488.086505
3493 65500.759109
3494 65507.027237
3495 65501.076908
3496 65490.658316
3497 65487.277885
3498 65493.634124
3499 65501.852359
3500 65503.058979
3501 65496.839353
Name: predicted_mean, dtype: float64
Gráfica lineplot modelo ARIMA para predecir el precio de Bitcoin con un horizonte de 7, 14, 21 y 28 días#
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
#Gráfica horizonte 7 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[0], color='#009900', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_7, y=test_7, ax=axes[0], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=predic_forecast7, ax=axes[0], label='Forecast', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[0].set_xlabel(None)
axes[0].legend(fontsize=14) # Mostrar la leyenda
axes[0].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 14 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[1], color='#009900', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_14, y=test_14, ax=axes[1], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=predic_forecast14, ax=axes[1], label='Forecast', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[1].set_xlabel(None)
axes[1].legend(fontsize=14) # Mostrar la leyenda
axes[1].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 21 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[2], color='#009900', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_21, y=test_21, ax=axes[2], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=predic_forecast21, ax=axes[2], label='Forecast', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[2].set_xlabel(None)
axes[2].legend(fontsize=14) # Mostrar la leyenda
axes[2].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[2].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 28 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[3], color='#009900', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_28, y=test_28, ax=axes[3], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=predic_forecast28, ax=axes[3], label='Forecast', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[3].set_xlabel('Fecha', fontsize=12)
axes[3].legend(fontsize=14) # Mostrar la leyenda
axes[3].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[3].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
plt.show()
El gráfico previo representa la predicción del modelo ARIMA sin utilizar el método rolling, con un horizonte de pronóstico de un período. En el contexto de nuestros modelos ARIMA, este período se define por los días definidos en cada uno de nuestros horizontes. El gráfico muestra la predicción para 7, 14, 21 y 28 días que le anteceden al último dato disponible en el conjunto de datos original. Además, se observan diferencias significativas entre las observaciones de prueba y las predicciones realizadas para cada uno de los horizontes.
Ejercicio 4.#
Realice tablas de error para los ejercicios 1 y 2, utilizando las métricas: MAPE, MAE, RMSE, MSE, R2. Además, agregue el gráfico de correlación entre la observación real y su predicción en el test, \( Corr(y_t, \tilde{y}_t) \).
Tablas de error para los ejercicios 2 (usando rolling) y 3 (sin utilizar rolling), utilizando las métricas: MAPE, MAE, RMSE, MSE, R2.#
Para medir el error de predicción cometido en las predicciones, utilizaremos las métricas usuales en análisis de series de tiempo: MAPE, MAE, RMSE, MSE, R2, la cuales se calcularán a través de la siguiente función:
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
def forecast_accuracy(forecast, actual, str_name):
# Calcula diferentes métricas de evaluación (MAPE, MAE, RMSE, MSE, R2)
# y las almacena en un DataFrame
mape = np.mean(np.abs(forecast - actual) / np.abs(actual)) # Calcular el Error Porcentual Absoluto Medio (MAPE)
r2 = r2_score(actual, forecast) # Calcular el Coeficiente de Determinación (R2)
rmse = mean_squared_error(actual, forecast, squared=False) # Calcular la Raíz del Error Cuadrático Medio (RMSE)
mse = mean_squared_error(actual, forecast, squared=True) # Calcular el Error Cuadrático Medio (MSE)
mae = mean_absolute_error(actual, forecast) # Calcular el Error Absoluto Medio (MAE)
# Crear un DataFrame con las métricas calculadas
df_acc = pd.DataFrame({
'MAPE': [mape],
'MAE': [mae],
'RMSE': [rmse],
'MSE': [mse],
'R2': [r2]
}, index=[str_name]) # Usar el nombre proporcionado como índice
return df_acc
Evaluación de las predicciones ejercicio 2 (usando rolling).#
Horizonte de 7 días
fraic7 = forecast_accuracy(np.array(yhat_7), np.array(test_7l), "AIC usando Rolling 7 días")
fraic7 = fraic7.round(3)
print(fraic7)
MAPE MAE RMSE MSE R2
AIC usando Rolling 7 días 0.021 1394.548 1797.175 3229839.082 0.559
Horizonte de 14 días
fraic14 =forecast_accuracy(np.array(yhat_14), np.array(test_14l), "AIC usando Rolling 14 días")
fraic14 = fraic14.round(3)
print(fraic14)
MAPE MAE RMSE MSE R2
AIC usando Rolling 14 días 0.022 1512.959 1967.627 3871556.705 0.335
Horizonte de 21 días
fraic21 = forecast_accuracy(np.array(yhat_21), np.array(test_21l), "AIC usando Rolling 21 días")
fraic21 = fraic21.round(3)
print(fraic21)
MAPE MAE RMSE MSE R2
AIC usando Rolling 21 días 0.021 1411.73 1810.354 3277380.241 0.309
Horizonte de 28 días
fraic28= forecast_accuracy(np.array(yhat_28), np.array(test_28l), "AIC usando Rolling 28 días")
fraic28r = fraic28.round(3)
print(fraic28r)
MAPE MAE RMSE MSE R2
AIC usando Rolling 28 días 0.024 1599.699 1957.321 3831106.52 0.537
Al observar estas métricas, podemos afirmar que el modelo ARIMA tiene un mejor desempeño en la predicción de series temporales para un horizonte de 7 días, mostrando una mayor precisión y capacidad para explicar la variabilidad en los datos en comparación con los horizontes de tiempo más largos.
Evaluación de las predicciones ejercicio 3 (Sin utilizar rolling).#
Horizonte de 7 días
faic7 = forecast_accuracy(np.array(predic_forecast7), np.array(test_7l), "AIC sin Rolling7 días")
faic7 = faic7.round(3)
print(faic7)
MAPE MAE RMSE MSE R2
AIC sin Rolling7 días 0.048 3281.089 3606.585 1.300746e+07 -0.776
Horizonte de 14 días
faic14 = forecast_accuracy(np.array(predic_forecast14), np.array(test_14l), "AIC sin Rolling 14 días")
faic14 = faic14.round(3)
print(faic14)
MAPE MAE RMSE MSE R2
AIC sin Rolling 14 días 0.046 3219.495 3668.064 1.345470e+07 -1.311
Horizonte de 21 días
faic21= forecast_accuracy(np.array(predic_forecast21), np.array(test_21l), "AIC sin Rolling 21 días")
faic21 = faic21.round(3)
print(faic21)
MAPE MAE RMSE MSE R2
AIC sin Rolling 21 días 0.051 3528.43 3891.219 1.514158e+07 -2.194
Horizonte de 28 días
faic28 = forecast_accuracy(np.array(predic_forecast28), np.array(test_28l), "AIC sin Rolling 28 días")
faic28 = faic28.round(3)
print(faic28)
MAPE MAE RMSE MSE R2
AIC sin Rolling 28 días 0.046 3126.999 3546.356 1.257664e+07 -0.521
Los resultados anteriores indican que el modelo ARIMA sin el método de Rolling tiene un desempeño notablemente inferior en la predicción de series temporales en contraste con el modelo usando Rolling. Las métricas de evaluación señalan una discrepancia más amplia entre las predicciones del modelo y los valores reales, junto con una capacidad restringida para explicar la variabilidad en los datos.
A continuación se presenta análisis de correlación entre variables (observación real y su predicción en el test, \( Corr(y_t, \tilde{y}_t) \).) para evaluar la relación lineal entre éstas a través de mapa de calor..
Gráfico de correlación entre la observación real y su predicción en el test, \( Corr(y_t, \tilde{y}_t) \).#
Gráfico de Correlación ejercicio 2 (usando rolling). .#
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=2, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
# Gráfica horizonte 7 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_7, y=test_7, ax=axes[0,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=yhat_7, ax=axes[0,0], label='Predicción', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0,0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[0,0].set_xlabel(None)
axes[0,0].legend(fontsize=10) # Mostrar la leyenda
axes[0,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_7l, y=yhat_7, ax=axes[0,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[0,1].plot(test_7l, test_7l, color='red', label='Correlación')
axes[0,1].set_title('Correlación entre valores reales y estimados Horizonte 7 días', fontsize=16)
axes[0,1].set_xlabel('Valores Reales', fontsize=12)
axes[0,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[0,1].legend(fontsize=10) # Mostrar la leyenda
axes[0,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[0,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_14, y=test_14, ax=axes[1,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=yhat_14, ax=axes[1,0], label='Predicción', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1,0].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[1,0].set_xlabel(None)
axes[1,0].legend(fontsize=10) # Mostrar la leyenda
axes[1,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_14l, y=yhat_14, ax=axes[1,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[1,1].plot(test_14l, test_14l, color='red', label='Correlación')
axes[1,1].set_title('Correlación entre valores reales y estimados Horizonte 14 días ', fontsize=16)
axes[1,1].set_xlabel('Valores Reales', fontsize=12)
axes[1,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[1,1].legend(fontsize=10) # Mostrar la leyenda
axes[1,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[1,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_21, y=test_21, ax=axes[2,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=yhat_21, ax=axes[2,0], label='Predicción', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2,0].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[2,0].set_xlabel(None)
#axes[2,0].legend(fontsize=10) # Mostrar la leyenda
axes[2,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[2,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_21l, y=yhat_21, ax=axes[2,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[2,1].plot(test_21l, test_21l, color='red', label='Correlación')
axes[2,1].set_title('Correlación entre valores reales y estimados Horizonte 21 días ', fontsize=16)
axes[2,1].set_xlabel('Valores Reales', fontsize=12)
axes[2,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[2,1].legend(fontsize=10) # Mostrar la leyenda
axes[2,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[2,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_28, y=test_28, ax=axes[3,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=yhat_28, ax=axes[3,0], label='Predicción', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3,0].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[3,0].set_xlabel(None)
#axes[3,0].legend(fontsize=10) # Mostrar la leyenda
axes[3,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[3,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_28l, y=yhat_28, ax=axes[3,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[3,1].plot(test_28l, test_28l, color='red', label='Correlación')
axes[3,1].set_title('Correlación entre valores reales y estimados Horizonte 28 días ', fontsize=16)
axes[3,1].set_xlabel('Valores Reales', fontsize=12)
axes[3,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[3,1].legend(fontsize=10) # Mostrar la leyenda
axes[3,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[3,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
plt.tight_layout() # Ajustar el espaciado entre subgráficos
plt.show()
El gráfico muestra predicciones para diferentes horizontes temporales (7, 14, 21 y 28 días) junto con observaciones reales de prueba. También se incluye un gráfico que correlaciona las predicciones con estas observaciones reales. En relación al primer gráfico del precio de cierre del Bitcoin, se aprecia que ambas líneas siguen tendencias similares y están próximas entre sí, lo que indica errores bajos. Sin embargo, se observa un sesgo en el tiempo que podría corregirse mediante mejoras en el modelo o la exploración de otras opciones que expliquen con mayor precisión la variabilidad en el tiempo. Los gráficos de autocorrelación revelan la ausencia de una correlación significativa entre los valores de la serie temporal y sus antecesores en los intervalos de 7, 14, 21 y 28 días. En resumen, no se observa un patrón claro o repetitivo en los datos a lo largo de estos horizontes.
Gráfico de Correlación ejercicio 3 (Sin utilizar rolling).#
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=2, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
# Gráfica horizonte 7 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_7, y=test_7, ax=axes[0,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=predic_forecast7, ax=axes[0,0], label='Predicción', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0,0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[0,0].set_xlabel(None)
axes[0,0].legend(fontsize=10) # Mostrar la leyenda
axes[0,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_7l, y=predic_forecast7, ax=axes[0,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[0,1].plot(test_7l, test_7l, color='red', label='Correlación')
axes[0,1].set_title('Correlación entre valores reales y estimados Horizonte 7 días', fontsize=16)
axes[0,1].set_xlabel('Valores Reales', fontsize=12)
axes[0,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[0,1].legend(fontsize=10) # Mostrar la leyenda
axes[0,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[0,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_14, y=test_14, ax=axes[1,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=predic_forecast14, ax=axes[1,0], label='Predicción', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1,0].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[1,0].set_xlabel(None)
axes[1,0].legend(fontsize=10) # Mostrar la leyenda
axes[1,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_14l, y=predic_forecast14, ax=axes[1,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[1,1].plot(test_14l, test_14l, color='red', label='Correlación')
axes[1,1].set_title('Correlación entre valores reales y estimados Horizonte 14 días ', fontsize=16)
axes[1,1].set_xlabel('Valores Reales', fontsize=12)
axes[1,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[1,1].legend(fontsize=10) # Mostrar la leyenda
axes[1,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[1,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_21, y=test_21, ax=axes[2,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=predic_forecast21, ax=axes[2,0], label='Predicción', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2,0].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[2,0].set_xlabel(None)
#axes[2,0].legend(fontsize=10) # Mostrar la leyenda
axes[2,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[2,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_21l, y=predic_forecast21, ax=axes[2,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[2,1].plot(test_21l, test_21l, color='red', label='Correlación')
axes[2,1].set_title('Correlación entre valores reales y estimados Horizonte 21 días ', fontsize=16)
axes[2,1].set_xlabel('Valores Reales', fontsize=12)
axes[2,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[2,1].legend(fontsize=10) # Mostrar la leyenda
axes[2,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[2,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_28, y=test_28, ax=axes[3,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=predic_forecast28, ax=axes[3,0], label='Predicción', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3,0].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[3,0].set_xlabel(None)
#axes[3,0].legend(fontsize=10) # Mostrar la leyenda
axes[3,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[3,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_28l, y=predic_forecast28, ax=axes[3,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[3,1].plot(test_28l, test_28l, color='red', label='Correlación')
axes[3,1].set_title('Correlación entre valores reales y estimados Horizonte 28 días ', fontsize=16)
axes[3,1].set_xlabel('Valores Reales', fontsize=12)
axes[3,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[3,1].legend(fontsize=10) # Mostrar la leyenda
axes[3,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[3,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
plt.tight_layout() # Ajustar el espaciado entre subgráficos
plt.show()
En el primer gráfico del precio de cierre del Bitcoin, se nota una discrepancia notable entre las observaciones reales de prueba y las predicciones, lo que sugiere la presencia de errores considerables. Por otro lado, los gráficos de autocorrelación no muestran una correlación significativa entre los valores de la serie temporal y sus antecedentes en los intervalos de 7, 14, 21 y 28 días. En resumen, no se identifica un patrón claro o repetitivo en los datos a lo largo de estos horizontes.
En términos de predicción del precio del Bitcoin, se puede concluir que el modelo ARIMA utilizando la técnica de rolling ofrece un rendimiento superior en comparación con el otro modelo considerado (ARIMA sin utilizar rolling).
Ejercicio 5.#
Repita el análisis desarrollado en los pasos anteriores, considerando ahora el criterio de inferencia Bayesiana (BIC) y el criterio de información de Hannan–Quinn (HQIC) para encontrar el mejor modelo ARIMA y, compare los errores con aquellos obtenidos con el criterio de Akaike.
Criterio de inferencia Bayesiana (BIC)#
Construcción de modelo ARIMA considerando el criterio de inferencia Bayesiana (BIC) para predecir el precio de Bitcoin con los siguientes horizontes: 7, 14, 21 y 28.#
from statsmodels.tsa.arima.model import ARIMA
import warnings
warnings.filterwarnings("ignore") # suprimir advertencias durante el ajuste del modelo.
def arima_model_fit_BIC(data_df):
# Realiza predicciones continuas usando un enfoque de desplazamiento
# y almacena las predicciones en una lista
data = data_df.copy()
n_BTC = len(data.Close)
train_size = n_BTC - 28 # Tamaño del conjunto de entrenamiento - 28 días
train = data.Close[:train_size] # Datos de entrenamiento (precios de cierre)
dates_train = data.Date[:train_size] # Fechas correspondientes a los datos de entrenamiento
#A través de la siguiente función que depende sólo del input `train` y retornarán los parámetros `p`, `d`, `q` y que definiendo el mejor modelo ARIMA con el menor criterio `BIC` como medida de bondad de ajuste.
#**Nota:** Consideramos el `método: mle`para el cálculo.
best_bic = np.inf
best_order = None
best_mdl = None
pq_rng = range(3)
d_rng = range(2)
for p in pq_rng:
for d in d_rng:
for q in pq_rng:
try:
# print(i, d, j)
tmp_mdl = ARIMA(train, order=(p,d,q)).fit()
tmp_bic = tmp_mdl.bic
if tmp_bic < best_bic:
best_bic = tmp_bic
best_order = (p, d, q)
best_mdl = tmp_mdl
except: continue
print('Best BIC:', best_bic)
print('Best Order:', best_order)
print('bic: {:6.5f} | order: {}'.format(best_bic, best_order))
model = ARIMA(train, order=best_order)
model_fit = model.fit()
return model_fit, train, dates_train, best_order
Indexación de parámetros para la función arima_model_fit_BIC()
La siguiente función devuelve los parámetros p, d, q que definen el mejor modelo ARIMA con el menor criterio BIC (Criterio de inferencia Bayesiana) como medida de bondad de ajuste. Además, proporciona los resultados del modelo ARIMA ajustado para datos de entrenamiento, incluyendo las fechas correspondientes. También incluye los datos y fechas del modelo ARIMA de prueba, aunque estos últimos dos no son directamente visibles en la salida de la función.
model_fit_BIC,train,dates_train,best_order_BIC = arima_model_fit_BIC(BTC_df_sorted)
Best BIC: 56500.07510711281
Best Order: (1, 1, 0)
bic: 56500.07511 | order: (1, 1, 0)
Según el criterio de BIC, se determinó que el modelo ARIMA óptimo es el (1,1,0).
Indexación de parámetros para la función arima_rolling()
La siguiente función devuelve las prediciones, con base a los parámetros p, d, q que definen el mejor modelo ARIMA con el menor criterio de inferencia Bayesiana (BIC) de bondad de ajuste, aprovechando datos históricos para pronosticar continuamente el precio futuro del Bitcoin durante un período (horizonte) específico.
Horizonte de 7 días
yhat_7_BIC = arima_rolling(train_7l, test_7l, best_order_BIC)
predicted=70686.741822, expected=63778.761719
predicted=64119.269789, expected=64062.203125
predicted=64048.394887, expected=67234.171875
predicted=67080.823962, expected=69958.812500
predicted=69837.285609, expected=69987.835938
predicted=69986.546273, expected=69455.343750
predicted=69479.008540, expected=70744.953125
Horizonte de 14 días
yhat_14_BIC = arima_rolling(train_14l, test_14l, best_order_BIC)
predicted=68398.041476, expected=63778.761719
predicted=64008.977909, expected=64062.203125
predicted=64048.378546, expected=67234.171875
predicted=67080.638715, expected=69958.812500
predicted=69837.106590, expected=69987.835938
predicted=69986.544362, expected=69455.343750
predicted=69479.043593, expected=70744.953125
predicted=70687.201487, expected=69892.828125
predicted=69931.343935, expected=69645.304688
predicted=69656.468100, expected=71333.648438
predicted=71257.217901, expected=69702.148438
predicted=69777.748584, expected=65446.972656
predicted=65631.927891, expected=65980.812500
predicted=65957.288898, expected=68508.843750
Horizonte de 21 días
yhat_21_BIC = arima_rolling(train_21l, test_21l, best_order_BIC)
predicted=70085.877875, expected=63778.761719
predicted=64071.200715, expected=64062.203125
predicted=64049.014585, expected=67234.171875
predicted=67087.740782, expected=69958.812500
predicted=69843.048328, expected=69987.835938
predicted=69986.607402, expected=69455.343750
predicted=69477.886962, expected=70744.953125
predicted=70690.006993, expected=69892.828125
predicted=69929.486737, expected=69645.304688
predicted=69655.929104, expected=71333.648438
predicted=71260.898011, expected=69702.148438
predicted=69774.173619, expected=65446.972656
predicted=65622.813590, expected=65980.812500
predicted=65958.433218, expected=68508.843750
predicted=68404.212247, expected=67837.640625
predicted=67865.796314, expected=68896.109375
predicted=68851.417954, expected=69362.554688
predicted=69342.960272, expected=71631.359375
predicted=71536.991482, expected=69139.015625
predicted=69248.028883, expected=70587.882812
predicted=70522.598743, expected=70060.609375
Horizonte de 28 días
yhat_28_BIC = arima_rolling(train_28l, test_28l, best_order_BIC)
predicted=63518.352600, expected=63778.761719
predicted=63771.670242, expected=64062.203125
predicted=64048.018445, expected=67234.171875
predicted=67076.592806, expected=69958.812500
predicted=69833.506049, expected=69987.835938
predicted=69986.506057, expected=69455.343750
predicted=69479.746338, expected=70744.953125
predicted=70685.504586, expected=69892.828125
predicted=69932.459581, expected=69645.304688
predicted=69656.792411, expected=71333.648438
predicted=71255.009741, expected=69702.148438
predicted=69779.856220, expected=65446.972656
predicted=65637.585289, expected=65980.812500
predicted=65956.588574, expected=68508.843750
predicted=68395.500722, expected=67837.640625
predicted=67868.109450, expected=68896.109375
predicted=68847.771008, expected=69362.554688
predicted=69341.353800, expected=71631.359375
predicted=71529.198974, expected=69139.015625
predicted=69256.592213, expected=70587.882812
predicted=70517.633853, expected=70060.609375
predicted=70086.312225, expected=67195.867188
predicted=67333.791342, expected=63821.472656
predicted=63970.581490, expected=65738.726562
predicted=65649.527754, expected=63426.210938
predicted=63537.652801, expected=63811.863281
predicted=63793.183001, expected=61276.691406
predicted=61400.450212, expected=63637.105469
Gráfica lineplot modelo ARIMA para predecir el precio de Bitcoin con un horizonte de 7, 14, 21 y 28 días usando el criterio BIC.#
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
#Gráfica horizonte 7 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[0], color='#CCCC00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_7, y=test_7, ax=axes[0], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=yhat_7_BIC , ax=axes[0], label='Forecast', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[0].set_xlabel(None)
axes[0].legend(fontsize=14) # Mostrar la leyenda
axes[0].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 14 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[1], color='#CCCC00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_14, y=test_14, ax=axes[1], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=yhat_14_BIC , ax=axes[1], label='Forecast', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[1].set_xlabel(None)
axes[1].legend(fontsize=14) # Mostrar la leyenda
axes[1].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 21 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[2], color='#CCCC00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_21, y=test_21, ax=axes[2], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=yhat_21_BIC , ax=axes[2], label='Forecast', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[2].set_xlabel(None)
axes[2].legend(fontsize=14) # Mostrar la leyenda
axes[2].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[2].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 28 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[3], color='#CCCC00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_28, y=test_28, ax=axes[3], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=yhat_28_BIC , ax=axes[3], label='Forecast', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[3].set_xlabel('Fecha', fontsize=12)
axes[3].legend(fontsize=14) # Mostrar la leyenda
axes[3].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[3].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
plt.show()
En el gráfico anterior se presentan las predicciones para horizontes de 7, 14, 21 y 28 días. La línea de color lima representa los datos utilizados para entrenar el modelo ARIMA. La línea azul muestra los datos reales u observaciones correspondientes a cada horizonte, mientras que la línea punteada indica las predicciones generadas por nuestro modelo ARIMA a partir de los datos de entrenamiento. Estas predicciones se comparan con los valores reales de prueba para evaluar la precisión del modelo.
También se aprecia un sesgo entre los datos reales de prueba y las predicciones proporcionadas por nuestro modelo ARIMA, basadas en los datos de entrenamiento.
A continuación se ajusta nuestro modelo ARIMA utilizando forecast() para los diferentes horizontes de predicción, 7, 14, 21 y 28 días, y así poder visualizar las predicciones del precio de cierre de la criptomoneda Bitcoin.
Horizonte de 7 días
predic_forecast7BIC = model_fit_BIC.forecast(7)
print(predic_forecast7BIC)
3474 65614.921428
3475 65608.621639
3476 65608.942914
3477 65608.926530
3478 65608.927365
3479 65608.927323
3480 65608.927325
Name: predicted_mean, dtype: float64
Horizonte de 14 días
predic_forecast14BIC = model_fit_BIC.forecast(14)
print(predic_forecast14BIC)
3474 65614.921428
3475 65608.621639
3476 65608.942914
3477 65608.926530
3478 65608.927365
3479 65608.927323
3480 65608.927325
3481 65608.927325
3482 65608.927325
3483 65608.927325
3484 65608.927325
3485 65608.927325
3486 65608.927325
3487 65608.927325
Name: predicted_mean, dtype: float64
Horizonte de 21 días
predic_forecast21BIC = model_fit_BIC.forecast(21)
print(predic_forecast21BIC)
3474 65614.921428
3475 65608.621639
3476 65608.942914
3477 65608.926530
3478 65608.927365
3479 65608.927323
3480 65608.927325
3481 65608.927325
3482 65608.927325
3483 65608.927325
3484 65608.927325
3485 65608.927325
3486 65608.927325
3487 65608.927325
3488 65608.927325
3489 65608.927325
3490 65608.927325
3491 65608.927325
3492 65608.927325
3493 65608.927325
3494 65608.927325
Name: predicted_mean, dtype: float64
Horizonte de 28 días
predic_forecast28BIC = model_fit_BIC.forecast(28)
print(predic_forecast28BIC)
3474 65614.921428
3475 65608.621639
3476 65608.942914
3477 65608.926530
3478 65608.927365
3479 65608.927323
3480 65608.927325
3481 65608.927325
3482 65608.927325
3483 65608.927325
3484 65608.927325
3485 65608.927325
3486 65608.927325
3487 65608.927325
3488 65608.927325
3489 65608.927325
3490 65608.927325
3491 65608.927325
3492 65608.927325
3493 65608.927325
3494 65608.927325
3495 65608.927325
3496 65608.927325
3497 65608.927325
3498 65608.927325
3499 65608.927325
3500 65608.927325
3501 65608.927325
Name: predicted_mean, dtype: float64
Gráfica lineplot modelo ARIMA para predecir el precio de Bitcoin con un horizonte de 7, 14, 21 y 28 días#
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
#Gráfica horizonte 7 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[0], color='#CCCC00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_7, y=test_7, ax=axes[0], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=predic_forecast7BIC, ax=axes[0], label='Forecast', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[0].set_xlabel(None)
axes[0].legend(fontsize=14) # Mostrar la leyenda
axes[0].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 14 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[1], color='#CCCC00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_14, y=test_14, ax=axes[1], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=predic_forecast14BIC, ax=axes[1], label='Forecast', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[1].set_xlabel(None)
axes[1].legend(fontsize=14) # Mostrar la leyenda
axes[1].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 21 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[2], color='#CCCC00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_21, y=test_21, ax=axes[2], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=predic_forecast21BIC, ax=axes[2], label='Forecast', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[2].set_xlabel(None)
axes[2].legend(fontsize=14) # Mostrar la leyenda
axes[2].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[2].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 28 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[3], color='#CCCC00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_28, y=test_28, ax=axes[3], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=predic_forecast28BIC, ax=axes[3], label='Forecast', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[3].set_xlabel('Fecha', fontsize=12)
axes[3].legend(fontsize=14) # Mostrar la leyenda
axes[3].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[3].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
plt.show()
El gráfico previo representa la predicción del modelo ARIMA sin utilizar el método rolling, con un horizonte de pronóstico. El gráfico muestra la predicción para 7, 14, 21 y 28 días que le anteceden al último dato disponible en el conjunto de datos original. Además, se observan diferencias significativas entre las observaciones de prueba y las predicciones realizadas para cada uno de los horizontes.
Tablas de error para los ejercicios 2 y 3, utilizando las métricas: MAPE, MAE, RMSE, MSE, R2.#
Evaluación de las predicciones ejercicio 2 (usando rolling).
Horizonte de 7 días
frbic7 = forecast_accuracy(np.array(yhat_7_BIC), np.array(test_7l), "BIC usando Rolling 7 días")
frbic7 = frbic7.round(3)
print(frbic7)
MAPE MAE RMSE MSE R2
BIC usando Rolling 7 días 0.032 2139.501 3118.216 9723270.853 -0.328
Horizonte de 14 días
frbic14 = forecast_accuracy(np.array(yhat_14_BIC), np.array(test_14l), "BIC usando Rolling 14 días")
frbic14 = frbic14.round(3)
print(frbic14)
MAPE MAE RMSE MSE R2
BIC usando Rolling 14 días 0.026 1730.585 2283.684 5215211.245 0.104
Horizonte de 21 días
frbic21 = forecast_accuracy(np.array(yhat_21_BIC), np.array(test_21l), "BIC usando Rolling 21 días")
frbic21 = frbic21.round(3)
print(frbic21)
MAPE MAE RMSE MSE R2
BIC usando Rolling 21 días 0.024 1641.197 2247.055 5049255.616 -0.065
Horizonte de 28 días
frbic28 = forecast_accuracy(np.array(yhat_28_BIC), np.array(test_28l), "BIC usando Rolling 28 días")
frbic28 = frbic28.round(3)
print(frbic28)
MAPE MAE RMSE MSE R2
BIC usando Rolling 28 días 0.023 1574.952 1951.188 3807134.823 0.54
Al observar estas métricas, podemos afirmar que el modelo ARIMA con la técnica de Rolling, utilizando el criterio BIC, tiene un desempeño relativamente bueno en la predicción de series temporales. La precisión de las predicciones mejora a medida que aumenta el horizonte de tiempo, y el modelo tiene una capacidad aceptable para explicar la variabilidad en los datos.
Evaluación de las predicciones ejercicio 3 (Sin utilizar rolling).
Horizonte de 7 días
fbic7 = forecast_accuracy(np.array(predic_forecast7BIC), np.array(test_7l), "BIC sin Rolling 7 días")
fbic7 = fbic7.round(3)
print(fbic7)
MAPE MAE RMSE MSE R2
BIC sin Rolling 7 días 0.047 3245.578 3539.053 1.252490e+07 -0.71
Horizonte de 14 días
fbic14 = forecast_accuracy(np.array(predic_forecast14BIC), np.array(test_14l), "BIC sin Rolling 14 días")
fbic14 = fbic14.round(3)
print(fbic14)
MAPE MAE RMSE MSE R2
BIC sin Rolling 14 días 0.046 3163.644 3589.86 1.288710e+07 -1.213
Horizonte de 21 días
fbic21 =forecast_accuracy(np.array(predic_forecast21BIC), np.array(test_21l), "BIC sin Rolling 21 días")
fbic21 = fbic21.round(3)
print(fbic21)
MAPE MAE RMSE MSE R2
BIC sin Rolling 21 días 0.05 3454.462 3802.383 1.445812e+07 -2.05
Horizonte de 28 días
fbic28 = forecast_accuracy(np.array(predic_forecast28BIC), np.array(test_28l), "BIC sin Rolling 28 días")
fbic28 = fbic28.round(3)
print(fbic28)
MAPE MAE RMSE MSE R2
BIC sin Rolling 28 días 0.045 3083.276 3484.664 1.214288e+07 -0.469
los resultados indican que el modelo ARIMA sin la técnica de Rolling y utilizando el criterio BIC tiene un desempeño deficiente en la predicción de series temporales. Las métricas de evaluación muestran una discrepancia significativa entre las predicciones del modelo y los valores reales, así como una capacidad limitada para explicar la variabilidad en los datos
A continuación se presenta análisis de correlación entre variables (observación real y su predicción en el test, \( Corr(y_t, \tilde{y}_t) \).) para evaluar la relación lineal entre éstas a través de mapa de calor..
Gráfico de correlación entre la observación real y su predicción en el test, \( Corr(y_t, \tilde{y}_t) \).#
Gráfico de Correlación ejercicio 2 (usando rolling). .
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=2, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
# Gráfica horizonte 7 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_7, y=test_7, ax=axes[0,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=yhat_7_BIC, ax=axes[0,0], label='Predicción', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0,0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[0,0].set_xlabel(None)
axes[0,0].legend(fontsize=10) # Mostrar la leyenda
axes[0,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_7l, y=yhat_7_BIC, ax=axes[0,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[0,1].plot(test_7l, test_7l, color='red', label='Correlación')
axes[0,1].set_title('Correlación entre valores reales y estimados Horizonte 7 días', fontsize=16)
axes[0,1].set_xlabel('Valores Reales', fontsize=12)
axes[0,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[0,1].legend(fontsize=10) # Mostrar la leyenda
axes[0,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[0,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_14, y=test_14, ax=axes[1,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=yhat_14_BIC, ax=axes[1,0], label='Predicción', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1,0].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[1,0].set_xlabel(None)
axes[1,0].legend(fontsize=10) # Mostrar la leyenda
axes[1,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_14l, y=yhat_14_BIC, ax=axes[1,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[1,1].plot(test_14l, test_14l, color='red', label='Correlación')
axes[1,1].set_title('Correlación entre valores reales y estimados Horizonte 14 días ', fontsize=16)
axes[1,1].set_xlabel('Valores Reales', fontsize=12)
axes[1,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[1,1].legend(fontsize=10) # Mostrar la leyenda
axes[1,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[1,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_21, y=test_21, ax=axes[2,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=yhat_21_BIC, ax=axes[2,0], label='Predicción', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2,0].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[2,0].set_xlabel(None)
#axes[2,0].legend(fontsize=10) # Mostrar la leyenda
axes[2,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[2,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_21l, y=yhat_21_BIC, ax=axes[2,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[2,1].plot(test_21l, test_21l, color='red', label='Correlación')
axes[2,1].set_title('Correlación entre valores reales y estimados Horizonte 21 días ', fontsize=16)
axes[2,1].set_xlabel('Valores Reales', fontsize=12)
axes[2,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[2,1].legend(fontsize=10) # Mostrar la leyenda
axes[2,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[2,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_28, y=test_28, ax=axes[3,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=yhat_28_BIC, ax=axes[3,0], label='Predicción', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3,0].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[3,0].set_xlabel(None)
#axes[3,0].legend(fontsize=10) # Mostrar la leyenda
axes[3,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[3,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_28l, y=yhat_28_BIC, ax=axes[3,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[3,1].plot(test_28l, test_28l, color='red', label='Correlación')
axes[3,1].set_title('Correlación entre valores reales y estimados Horizonte 28 días ', fontsize=16)
axes[3,1].set_xlabel('Valores Reales', fontsize=12)
axes[3,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[3,1].legend(fontsize=10) # Mostrar la leyenda
axes[3,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[3,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
plt.tight_layout() # Ajustar el espaciado entre subgráficos
plt.show()
El gráfico muestra predicciones para diferentes horizontes temporales (7, 14, 21 y 28 días) junto con observaciones reales de prueba. También se incluye un gráfico que correlaciona las predicciones con estas observaciones reales. En relación al primer gráfico del precio de cierre del Bitcoin, se aprecia que ambas líneas siguen tendencias similares y están próximas entre sí, lo que indica errores bajos. Sin embargo, se observa un sesgo en el tiempo que podría corregirse mediante mejoras en el modelo o la exploración de otras opciones que expliquen con mayor precisión la variabilidad en el tiempo. Los gráficos de autocorrelación revelan la ausencia de una correlación significativa entre los valores de la serie temporal y sus antecesores en los intervalos de 7, 14, 21 y 28 días. En resumen, no se observa un patrón claro o repetitivo en los datos a lo largo de estos horizontes.
Gráfico de Correlación ejercicio 3 (Sin utilizar rolling).
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=2, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
# Gráfica horizonte 7 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_7, y=test_7, ax=axes[0,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=predic_forecast7BIC, ax=axes[0,0], label='Predicción', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0,0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[0,0].set_xlabel(None)
axes[0,0].legend(fontsize=10) # Mostrar la leyenda
axes[0,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_7l, y=predic_forecast7BIC, ax=axes[0,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[0,1].plot(test_7l, test_7l, color='red', label='Correlación')
axes[0,1].set_title('Correlación entre valores reales y estimados Horizonte 7 días', fontsize=16)
axes[0,1].set_xlabel('Valores Reales', fontsize=12)
axes[0,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[0,1].legend(fontsize=10) # Mostrar la leyenda
axes[0,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[0,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_14, y=test_14, ax=axes[1,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=predic_forecast14BIC, ax=axes[1,0], label='Predicción', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1,0].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[1,0].set_xlabel(None)
axes[1,0].legend(fontsize=10) # Mostrar la leyenda
axes[1,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_14l, y=predic_forecast14BIC, ax=axes[1,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[1,1].plot(test_14l, test_14l, color='red', label='Correlación')
axes[1,1].set_title('Correlación entre valores reales y estimados Horizonte 14 días ', fontsize=16)
axes[1,1].set_xlabel('Valores Reales', fontsize=12)
axes[1,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[1,1].legend(fontsize=10) # Mostrar la leyenda
axes[1,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[1,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_21, y=test_21, ax=axes[2,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=predic_forecast21BIC, ax=axes[2,0], label='Predicción', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2,0].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[2,0].set_xlabel(None)
#axes[2,0].legend(fontsize=10) # Mostrar la leyenda
axes[2,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[2,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_21l, y=predic_forecast21BIC, ax=axes[2,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[2,1].plot(test_21l, test_21l, color='red', label='Correlación')
axes[2,1].set_title('Correlación entre valores reales y estimados Horizonte 21 días ', fontsize=16)
axes[2,1].set_xlabel('Valores Reales', fontsize=12)
axes[2,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[2,1].legend(fontsize=10) # Mostrar la leyenda
axes[2,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[2,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_28, y=test_28, ax=axes[3,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=predic_forecast28BIC, ax=axes[3,0], label='Predicción', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3,0].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[3,0].set_xlabel(None)
#axes[3,0].legend(fontsize=10) # Mostrar la leyenda
axes[3,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[3,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_28l, y=predic_forecast28BIC, ax=axes[3,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[3,1].plot(test_28l, test_28l, color='red', label='Correlación')
axes[3,1].set_title('Correlación entre valores reales y estimados Horizonte 28 días ', fontsize=16)
axes[3,1].set_xlabel('Valores Reales', fontsize=12)
axes[3,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[3,1].legend(fontsize=10) # Mostrar la leyenda
axes[3,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[3,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
plt.tight_layout() # Ajustar el espaciado entre subgráficos
plt.show()
En el primer gráfico del precio de cierre del Bitcoin, se nota una discrepancia notable entre las observaciones reales de prueba y las predicciones, lo que sugiere la presencia de errores considerables. Por otro lado, los gráficos de autocorrelación no muestran una correlación significativa entre los valores de la serie temporal y sus antecedentes en los intervalos de 7, 14, 21 y 28 días. En resumen, no se identifica un patrón claro o repetitivo en los datos a lo largo de estos horizontes.
En términos de predicción del precio del Bitcoin, se puede concluir que el modelo ARIMA utilizando la técnica de rolling ofrece un rendimiento superior en comparación con el otro modelo considerado (ARIMA sin utilizar rolling).
Criterio de información de Hannan-Quinn (HQIC)#
Construcción de modelo ARIMA considerando el criterio de información de Hannan-Quinn (HQIC) para predecir el precio de Bitcoin con los siguientes horizontes: 7, 14, 21 y 28.#
from statsmodels.tsa.arima.model import ARIMA
import warnings
warnings.filterwarnings("ignore") # suprimir advertencias durante el ajuste del modelo.
def arima_model_fit_HQIC(data_df):
# Realiza predicciones continuas usando un enfoque de desplazamiento
# y almacena las predicciones en una lista
data = data_df.copy()
n_BTC = len(data.Close)
train_size = n_BTC - 28 # Tamaño del conjunto de entrenamiento - 28 días
train = data.Close[:train_size] # Datos de entrenamiento (precios de cierre)
dates_train = data.Date[:train_size] # Fechas correspondientes a los datos de entrenamiento
#A través de la siguiente función que depende sólo del input `train` y retornarán los parámetros `p`, `d`, `q` y que definiendo el mejor modelo ARIMA con el menor criterio `BIC` como medida de bondad de ajuste.
#**Nota:** Consideramos el `método: mle`para el cálculo.
best_hqic = np.inf
best_order = None
best_mdl = None
pq_rng = range(3)
d_rng = range(2)
for p in pq_rng:
for d in d_rng:
for q in pq_rng:
try:
# print(i, d, j)
tmp_mdl = ARIMA(train, order=(p,d,q)).fit()
tmp_hqic = tmp_mdl.hqic
if tmp_hqic < best_hqic :
best_hqic = tmp_hqic
best_order = (p,d,q)
best_mdl = tmp_mdl
except: continue
print('Best BIC:', best_hqic)
print('Best Order:', best_order)
print('bic: {:6.5f} | order: {}'.format(best_hqic, best_order))
model = ARIMA(train, order=best_order)
model_fit = model.fit()
return model_fit, train, dates_train, best_order
Indexación de parámetros para la función arima_model_fit_HQIC()
La siguiente función devuelve los parámetros p, d, q que definen el mejor modelo ARIMA con el menor criterio HQIC (Criterio de información de Hanna-Quinn) como medida de bondad de ajuste. Además, proporciona los resultados del modelo ARIMA ajustado para datos de entrenamiento, incluyendo las fechas correspondientes. También incluye los datos y fechas del modelo ARIMA de prueba, aunque estos últimos dos no son directamente visibles en la salida de la función.
model_fit_HQIC, train, dates_train,best_order_HQIC = arima_model_fit_HQIC(BTC_df_sorted)
Best BIC: 56483.02518022764
Best Order: (2, 1, 2)
bic: 56483.02518 | order: (2, 1, 2)
Según el criterio de BIC, se determinó que el modelo ARIMA óptimo es el (2,1,2).
Indexación de parámetros para la función arima_rolling()
Horizonte de 7 días
yhat_7_HQIC = arima_rolling(train_7l, test_7l, best_order_HQIC)
predicted=70811.697824, expected=63778.761719
predicted=63702.802637, expected=64062.203125
predicted=63731.895968, expected=67234.171875
predicted=67074.831857, expected=69958.812500
predicted=69739.442330, expected=69987.835938
predicted=70049.771137, expected=69455.343750
predicted=69607.897443, expected=70744.953125
Horizonte de 14 días
yhat_14_HQIC = arima_rolling(train_14l, test_14l, best_order_HQIC)
predicted=68306.468761, expected=63778.761719
predicted=63775.368240, expected=64062.203125
predicted=64178.394141, expected=67234.171875
predicted=67186.536205, expected=69958.812500
predicted=69778.582631, expected=69987.835938
predicted=69967.571815, expected=69455.343750
predicted=69628.479481, expected=70744.953125
predicted=70829.428617, expected=69892.828125
predicted=69894.575368, expected=69645.304688
predicted=69553.891887, expected=71333.648438
predicted=71159.662792, expected=69702.148438
predicted=69775.632991, expected=65446.972656
predicted=65826.978295, expected=65980.812500
predicted=66078.119657, expected=68508.843750
Horizonte de 21 días
yhat_21_HQIC = arima_rolling(train_21l, test_21l, best_order_HQIC)
predicted=69670.842268, expected=63778.761719
predicted=63893.959855, expected=64062.203125
predicted=64490.942495, expected=67234.171875
predicted=67380.598128, expected=69958.812500
predicted=69595.609441, expected=69987.835938
predicted=69540.166665, expected=69455.343750
predicted=69443.389089, expected=70744.953125
predicted=71112.269611, expected=69892.828125
predicted=70240.887507, expected=69645.304688
predicted=69593.885299, expected=71333.648438
predicted=70902.588673, expected=69702.148438
predicted=69447.439757, expected=65446.972656
predicted=65780.181813, expected=65980.812500
predicted=66478.532043, expected=68508.843750
predicted=68532.969471, expected=67837.640625
predicted=67392.225978, expected=68896.109375
predicted=68467.023232, expected=69362.554688
predicted=69410.072867, expected=71631.359375
predicted=71997.733389, expected=69139.015625
predicted=69491.377469, expected=70587.882812
predicted=70475.107264, expected=70060.609375
Horizonte de 28 días
yhat_28_HQIC = arima_rolling(train_28l, test_28l, best_order_HQIC)
predicted=63546.231706, expected=63778.761719
predicted=63740.095431, expected=64062.203125
predicted=64080.281442, expected=67234.171875
predicted=67134.925950, expected=69958.812500
predicted=69926.332335, expected=69987.835938
predicted=70204.449870, expected=69455.343750
predicted=69738.947876, expected=70744.953125
predicted=70799.933774, expected=69892.828125
predicted=69876.296975, expected=69645.304688
predicted=69543.947359, expected=71333.648438
predicted=71136.912064, expected=69702.148438
predicted=69758.093163, expected=65446.972656
predicted=65733.890465, expected=65980.812500
predicted=65968.168204, expected=68508.843750
predicted=68227.812885, expected=67837.640625
predicted=67690.892240, expected=68896.109375
predicted=68860.655734, expected=69362.554688
predicted=69481.074711, expected=71631.359375
predicted=71714.529003, expected=69139.015625
predicted=69407.234820, expected=70587.882812
predicted=70588.746159, expected=70060.609375
predicted=69987.779760, expected=67195.867188
predicted=67226.844741, expected=63821.472656
predicted=63844.660023, expected=65738.726562
predicted=65460.133302, expected=63426.210938
predicted=63315.296428, expected=63811.863281
predicted=63722.237898, expected=61276.691406
predicted=61416.235410, expected=63637.105469
Gráfica lineplot modelo ARIMA para predecir el precio de Bitcoin con un horizonte de 7, 14, 21 y 28 días usando el criterio BIC.#
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
#Gráfica horizonte 7 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[0], color='#00FF00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_7, y=test_7, ax=axes[0], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=yhat_7_HQIC , ax=axes[0], label='Forecast', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[0].set_xlabel(None)
axes[0].legend(fontsize=14) # Mostrar la leyenda
axes[0].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 14 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[1], color='#00FF00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_14, y=test_14, ax=axes[1], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=yhat_14_HQIC , ax=axes[1], label='Forecast', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[1].set_xlabel(None)
axes[1].legend(fontsize=14) # Mostrar la leyenda
axes[1].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 21 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[2], color='#00FF00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_21, y=test_21, ax=axes[2], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=yhat_21_HQIC , ax=axes[2], label='Forecast', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[2].set_xlabel(None)
axes[2].legend(fontsize=14) # Mostrar la leyenda
axes[2].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[2].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 28 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[3], color='#00FF00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_28, y=test_28, ax=axes[3], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=yhat_28_HQIC , ax=axes[3], label='Forecast', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[3].set_xlabel('Fecha', fontsize=12)
axes[3].legend(fontsize=14) # Mostrar la leyenda
axes[3].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[3].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
plt.show()
A continuación se ajusta nuestro modelo ARIMA al conjunto de entrenamiento utilizando forecast() para los diferentes horizontes de predicción, 7, 14, 21 y 28 días, para la visualización de las predicciones del precio de cierre de la criptomoneda Bitcoin.
Horizonte de 7 días
predic_forecast7HQIC = model_fit_HQIC.forecast(7)
print(predic_forecast7HQIC)
3474 65458.494464
3475 65469.217327
3476 65506.959254
3477 65528.716848
3478 65513.547322
3479 65481.913168
3480 65469.104822
Name: predicted_mean, dtype: float64
Horizonte de 14 días
predic_forecast14HQIC = model_fit_HQIC.forecast(14)
print(predic_forecast14HQIC)
3474 65458.494464
3475 65469.217327
3476 65506.959254
3477 65528.716848
3478 65513.547322
3479 65481.913168
3480 65469.104822
3481 65486.302922
3482 65511.754461
3483 65517.675011
3484 65500.216718
3485 65480.598282
3486 65479.724074
3487 65496.228503
Name: predicted_mean, dtype: float64
Horizonte de 21 días
predic_forecast21HQIC = model_fit_HQIC.forecast(21)
print(predic_forecast21HQIC)
3474 65458.494464
3475 65469.217327
3476 65506.959254
3477 65528.716848
3478 65513.547322
3479 65481.913168
3480 65469.104822
3481 65486.302922
3482 65511.754461
3483 65517.675011
3484 65500.216718
3485 65480.598282
3486 65479.724074
3487 65496.228503
3488 65510.628019
3489 65508.029204
3490 65493.238830
3491 65483.304624
3492 65488.086505
3493 65500.759109
3494 65507.027237
Name: predicted_mean, dtype: float64
Horizonte de 28 días
predic_forecast28HQIC = model_fit_HQIC.forecast(28)
print(predic_forecast28HQIC)
3474 65458.494464
3475 65469.217327
3476 65506.959254
3477 65528.716848
3478 65513.547322
3479 65481.913168
3480 65469.104822
3481 65486.302922
3482 65511.754461
3483 65517.675011
3484 65500.216718
3485 65480.598282
3486 65479.724074
3487 65496.228503
3488 65510.628019
3489 65508.029204
3490 65493.238830
3491 65483.304624
3492 65488.086505
3493 65500.759109
3494 65507.027237
3495 65501.076908
3496 65490.658316
3497 65487.277885
3498 65493.634124
3499 65501.852359
3500 65503.058979
3501 65496.839353
Name: predicted_mean, dtype: float64
Gráfica lineplot modelo ARIMA para predecir el precio de Bitcoin con un horizonte de 7, 14, 21 y 28 días#
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
#Gráfica horizonte 7 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[0], color='#00FF00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_7, y=test_7, ax=axes[0], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=predic_forecast7HQIC, ax=axes[0], label='Forecast', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[0].set_xlabel(None)
axes[0].legend(fontsize=14) # Mostrar la leyenda
axes[0].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[0].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 14 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[1], color='#00FF00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_14, y=test_14, ax=axes[1], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=predic_forecast14HQIC, ax=axes[1], label='Forecast', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[1].set_xlabel(None)
axes[1].legend(fontsize=14) # Mostrar la leyenda
axes[1].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[1].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 21 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[2], color='#00FF00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_21, y=test_21, ax=axes[2], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=predic_forecast21HQIC, ax=axes[2], label='Forecast', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[2].set_xlabel(None)
axes[2].legend(fontsize=14) # Mostrar la leyenda
axes[2].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[2].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
#Gráfica horizonte 28 días.
sns.lineplot(x=dates_train[-100:], y=train[-100:], ax=axes[3], color='#00FF00', label='Training Data', linewidth=2) # Trama de línea para los datos de entrenamiento (últimos 100 días)
sns.lineplot(x=dates_28, y=test_28, ax=axes[3], label='Test Data', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=predic_forecast28HQIC, ax=axes[3], label='Forecast', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3].set_ylabel('Precio de Cierre BTC', fontsize=14)
axes[3].set_xlabel('Fecha', fontsize=12)
axes[3].legend(fontsize=14) # Mostrar la leyenda
axes[3].tick_params(axis='x', labelsize=13) # Solo para el eje x (inferior)
axes[3].tick_params(axis='y', labelsize=13) # Solo para el eje y (izquierdo)
plt.show()
El gráfico previo representa la predicción del modelo ARIMA sin utilizar el método rolling, con un horizonte de pronóstico. El gráfico muestra la predicción para 7, 14, 21 y 28 días que le anteceden al último dato disponible en el conjunto de datos original. Además, se observan diferencias significativas entre las observaciones de prueba y las predicciones realizadas para cada uno de los horizontes.
Tablas de error para los ejercicios 2 y 3, utilizando las métricas: MAPE, MAE, RMSE, MSE, R2.#
Evaluación de las predicciones ejercicio 2 (usando rolling).
Horizonte de 7 días
frhqic7 = forecast_accuracy(np.array(yhat_7_HQIC), np.array(test_7l), "HQIC usando Rolling 7 días")
frhqic7 = frhqic7.round(3)
print(frhqic7)
MAPE MAE RMSE MSE R2
HQIC usando Rolling 7 días 0.034 2251.21 3204.519 1.026894e+07 -0.402
Horizonte de 14 días
frhqic14 = forecast_accuracy(np.array(yhat_14_HQIC), np.array(test_14l), "HQIC usando Rolling 14 días")
frhqic14 = frhqic14.round(3)
print(frhqic14)
MAPE MAE RMSE MSE R2
HQIC usando Rolling 14 días 0.025 1701.208 2237.01 5004214.24 0.141
Horizonte de 21 días
frhqic21 = forecast_accuracy(np.array(yhat_21_HQIC), np.array(test_21l), "HQIC usando Rolling 21 días")
frhqic21 = frhqic21.round(3)
print(frhqic21)
MAPE MAE RMSE MSE R2
HQIC usando Rolling 21 días 0.024 1611.084 2130.011 4536947.766 0.043
Horizonte de 28 días
frhqic28= forecast_accuracy(np.array(yhat_28_HQIC), np.array(test_28l), "HQIC usando Rolling 28 días")
frhqic28 = frhqic28.round(3)
print(frhqic28)
MAPE MAE RMSE MSE R2
HQIC usando Rolling 28 días 0.023 1558.23 1926.854 3712766.082 0.551
Al observar estas métricas, podemos afirmar que el modelo ARIMA utilizando el criterio HQIC y la técnica de Rolling muestra una buena capacidad predictiva en general, con un rendimiento especialmente fuerte en el horizonte de 28 días en términos de precisión y capacidad para explicar la variabilidad en los datos.
Evaluación de las predicciones ejercicio 3 (Sin utilizar rolling).
Horizonte de 7 días
fhqic7 = forecast_accuracy(np.array(predic_forecast7HQIC), np.array(test_7l), "HQIC sin Rolling 7 días")
fhqic7 = fhqic7.round(3)
print(fhqic7)
MAPE MAE RMSE MSE R2
HQIC sin Rolling 7 días 0.048 3281.089 3606.585 1.300746e+07 -0.776
Horizonte de 14 días
fhqic14 = forecast_accuracy(np.array(predic_forecast14HQIC), np.array(test_14l), "HQIC sin Rolling 14 días")
fhqic14 = fhqic14.round(3)
print(fhqic14)
MAPE MAE RMSE MSE R2
HQIC sin Rolling 14 días 0.046 3219.495 3668.064 1.345470e+07 -1.311
Horizonte de 21 días
fhqic21 = forecast_accuracy(np.array(predic_forecast21HQIC), np.array(test_21l), "HQIC sin Rolling 21 días")
fhqic21 = fhqic21.round(3)
print(fhqic21)
MAPE MAE RMSE MSE R2
HQIC sin Rolling 21 días 0.051 3528.43 3891.219 1.514158e+07 -2.194
Horizonte de 28 días
fhqic28 = forecast_accuracy(np.array(predic_forecast28HQIC), np.array(test_28l), "HQIC sin Rolling 28 días")
fhqic28 = fhqic28.round(3)
print(fhqic28)
MAPE MAE RMSE MSE R2
HQIC sin Rolling 28 días 0.046 3126.999 3546.356 1.257664e+07 -0.521
Los resultados indican que el modelo ARIMA con el criterio HQIC sin la técnica de Rolling no logra capturar de manera efectiva la variabilidad en los datos para ninguno de los horizontes de tiempo considerados. Las métricas de evaluación revelan una discrepancia significativa entre las predicciones del modelo y los valores reales, así como una capacidad limitada para explicar la variabilidad en los datos.
A continuación se presenta análisis de correlación entre variables (observación real y su predicción en el test, \( Corr(y_t, \tilde{y}_t) \).) para evaluar la relación lineal entre éstas a través de mapa de calor..
Gráfico de correlación entre la observación real y su predicción en el test, \( Corr(y_t, \tilde{y}_t) \).#
Gráfico de Correlación ejercicio 2 (usando rolling).
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=2, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
# Gráfica horizonte 7 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_7, y=test_7, ax=axes[0,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=yhat_7_HQIC, ax=axes[0,0], label='Predicción', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0,0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[0,0].set_xlabel(None)
axes[0,0].legend(fontsize=10) # Mostrar la leyenda
axes[0,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_7l, y=yhat_7_HQIC, ax=axes[0,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[0,1].plot(test_7l, test_7l, color='red', label='Correlación')
axes[0,1].set_title('Correlación entre valores reales y estimados Horizonte 7 días', fontsize=16)
axes[0,1].set_xlabel('Valores Reales', fontsize=12)
axes[0,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[0,1].legend(fontsize=10) # Mostrar la leyenda
axes[0,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[0,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_14, y=test_14, ax=axes[1,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=yhat_14_HQIC, ax=axes[1,0], label='Predicción', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1,0].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[1,0].set_xlabel(None)
axes[1,0].legend(fontsize=10) # Mostrar la leyenda
axes[1,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_14l, y=yhat_14_HQIC, ax=axes[1,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[1,1].plot(test_14l, test_14l, color='red', label='Correlación')
axes[1,1].set_title('Correlación entre valores reales y estimados Horizonte 14 días ', fontsize=16)
axes[1,1].set_xlabel('Valores Reales', fontsize=12)
axes[1,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[1,1].legend(fontsize=10) # Mostrar la leyenda
axes[1,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[1,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 21 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_21, y=test_21, ax=axes[2,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=yhat_21_HQIC, ax=axes[2,0], label='Predicción', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2,0].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[2,0].set_xlabel(None)
#axes[2,0].legend(fontsize=10) # Mostrar la leyenda
axes[2,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[2,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_21l, y=yhat_21_HQIC, ax=axes[2,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[2,1].plot(test_21l, test_21l, color='red', label='Correlación')
axes[2,1].set_title('Correlación entre valores reales y estimados Horizonte 21 días ', fontsize=16)
axes[2,1].set_xlabel('Valores Reales', fontsize=12)
axes[2,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[2,1].legend(fontsize=10) # Mostrar la leyenda
axes[2,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[2,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 28 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_28, y=test_28, ax=axes[3,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=yhat_28_HQIC, ax=axes[3,0], label='Predicción', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3,0].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[3,0].set_xlabel(None)
#axes[3,0].legend(fontsize=10) # Mostrar la leyenda
axes[3,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[3,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_28l, y=yhat_28_HQIC, ax=axes[3,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[3,1].plot(test_28l, test_28l, color='red', label='Correlación')
axes[3,1].set_title('Correlación entre valores reales y estimados Horizonte 28 días ', fontsize=16)
axes[3,1].set_xlabel('Valores Reales', fontsize=12)
axes[3,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[3,1].legend(fontsize=10) # Mostrar la leyenda
axes[3,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[3,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
plt.tight_layout() # Ajustar el espaciado entre subgráficos
plt.show()
El gráfico muestra predicciones para diferentes horizontes temporales (7, 14, 21 y 28 días) junto con observaciones reales de prueba. También se incluye un gráfico que correlaciona las predicciones con estas observaciones reales. En relación al primer gráfico del precio de cierre del Bitcoin, se aprecia que ambas líneas siguen tendencias similares y están próximas entre sí, lo que indica errores bajos. Sin embargo, se observa un sesgo en el tiempo que podría corregirse mediante mejoras en el modelo o la exploración de otras opciones que expliquen con mayor precisión la variabilidad en el tiempo. Los gráficos de autocorrelación revelan la ausencia de una correlación significativa entre los valores de la serie temporal y sus antecesores en los intervalos de 7, 14, 21 y 28 días. En resumen, no se observa un patrón claro o repetitivo en los datos a lo largo de estos horizontes.
Gráfico de Correlación ejercicio 3 (Sin utilizar rolling).
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(nrows=4, ncols=2, figsize=(25, 25)) # Crear la figura y el eje de la subtrama
# Gráfica horizonte 7 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_7, y=test_7, ax=axes[0,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_7, y=predic_forecast7HQIC, ax=axes[0,0], label='Predicción', color='#CC0000', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[0,0].set_title('Predicción de precio de Cierre BTC Horizonte 7 días', fontsize=16)
axes[0,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[0,0].set_xlabel(None)
axes[0,0].legend(fontsize=10) # Mostrar la leyenda
axes[0,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[0,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_7l, y=predic_forecast7HQIC, ax=axes[0,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[0,1].plot(test_7l, test_7l, color='red', label='Correlación')
axes[0,1].set_title('Correlación entre valores reales y estimados Horizonte 7 días', fontsize=16)
axes[0,1].set_xlabel('Valores Reales', fontsize=12)
axes[0,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[0,1].legend(fontsize=10) # Mostrar la leyenda
axes[0,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[0,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 14 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_14, y=test_14, ax=axes[1,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_14, y=predic_forecast14HQIC, ax=axes[1,0], label='Predicción', color='#330099', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[1,0].set_title('Predicción de precio de Cierre BTC Horizonte 14 días', fontsize=16)
axes[1,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[1,0].set_xlabel(None)
axes[1,0].legend(fontsize=10) # Mostrar la leyenda
axes[1,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[1,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_14l, y=predic_forecast14HQIC, ax=axes[1,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[1,1].plot(test_14l, test_14l, color='red', label='Correlación')
axes[1,1].set_title('Correlación entre valores reales y estimados Horizonte 14 días ', fontsize=16)
axes[1,1].set_xlabel('Valores Reales', fontsize=12)
axes[1,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[1,1].legend(fontsize=10) # Mostrar la leyenda
axes[1,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[1,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 21 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_21, y=test_21, ax=axes[2,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_21, y=predic_forecast21HQIC, ax=axes[2,0], label='Predicción', color='#E91E63', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[2,0].set_title('Predicción de precio de Cierre BTC Horizonte 21 días', fontsize=16)
axes[2,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[2,0].set_xlabel(None)
#axes[2,0].legend(fontsize=10) # Mostrar la leyenda
axes[2,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[2,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_21l, y=predic_forecast21HQIC, ax=axes[2,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[2,1].plot(test_21l, test_21l, color='red', label='Correlación')
axes[2,1].set_title('Correlación entre valores reales y estimados Horizonte 21 días ', fontsize=16)
axes[2,1].set_xlabel('Valores Reales', fontsize=12)
axes[2,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[2,1].legend(fontsize=10) # Mostrar la leyenda
axes[2,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[2,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
# Gráfica horizonte 28 días.
#Gráfica valores de prueba vs estimado
sns.lineplot(x=dates_28, y=test_28, ax=axes[3,0], label='Observación real', color='#008080', linewidth=2)# Trama de línea para los datos de prueba
sns.lineplot(x=dates_28, y=predic_forecast28HQIC, ax=axes[3,0], label='Predicción', color='#FF5722', linewidth=2, linestyle='--') # Trama de línea para los datos de pronóstico
axes[3,0].set_title('Predicción de precio de Cierre BTC Horizonte 28 días', fontsize=16)
axes[3,0].set_ylabel('Precio de Cierre BTC', fontsize=10)
axes[3,0].set_xlabel(None)
#axes[3,0].legend(fontsize=10) # Mostrar la leyenda
axes[3,0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axes[3,0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Gráfico de dispersión para la correlación entre los valores reales y estimados
sns.scatterplot(x=test_28l, y=predic_forecast28HQIC, ax=axes[3,1], color='blue', label='Real vs Estimado')
# Línea de referencia para una correlación perfecta
axes[3,1].plot(test_28l, test_28l, color='red', label='Correlación')
axes[3,1].set_title('Correlación entre valores reales y estimados Horizonte 28 días ', fontsize=16)
axes[3,1].set_xlabel('Valores Reales', fontsize=12)
axes[3,1].set_ylabel('Valores Estimados', fontsize=12)
#axes[3,1].legend(fontsize=10) # Mostrar la leyenda
axes[3,1].tick_params(axis='x', labelsize=10) # Tamaño de las etiquetas del eje x (inferior)
axes[3,1].tick_params(axis='y', labelsize=10) # Tamaño de las etiquetas del eje y (izquierdo)
plt.tight_layout() # Ajustar el espaciado entre subgráficos
plt.show()
En el primer gráfico del precio de cierre del Bitcoin, se nota una discrepancia notable entre las observaciones reales de prueba y las predicciones, lo que sugiere la presencia de errores considerables. Por otro lado, los gráficos de autocorrelación no muestran una correlación significativa entre los valores de la serie temporal y sus antecedentes en los intervalos de 7, 14, 21 y 28 días. En resumen, no se identifica un patrón claro o repetitivo en los datos a lo largo de estos horizontes.
En términos de predicción del precio del Bitcoin, se puede concluir que el modelo ARIMA utilizando la técnica de rolling ofrece un rendimiento superior en comparación con el otro modelo considerado (ARIMA sin utilizar rolling).
Ejercicio 6.#
Realice tests de normalidad e independencia para los residuales obtenidos para cada predicción, en cada caso agregue las correspondientes conclusiones.
Test de Normalidad de los residuales a través de Kolmogorov-Smirnov#
Planteamiento de Hipótesis:
Críterios de aceptación y/o rechazo:
Sí el P-value \(< 0.05 \), se rechaza la hipótesis nula con un a significancia \( \alpha = 0.05\), es decir que los datos no siguen una distribución normal.
Test de Independiencia de los residuales a través del Estadístico de Durbin Watson#
El estadístico de Durbin-Watson (DW) es una medida utilizada para evaluar la presencia de autocorrelación en los residuos de un modelo de regresión, éste toma valores entre 0 y 4. Un valor de DW cercano a 2 sugiere que no hay autocorrelación serial en los residuos. Esto significa que los residuos en un momento dado no están correlacionados con los residuos en momentos anteriores. Un valor de 2 implica la ausencia total de autocorrelación.Cuando el valor de DW se acerca a 0, indica autocorrelación positiva en los residuos. Esto significa que los residuos en un momento dado están correlacionados positivamente con los residuos en momentos anteriores. Por otro lado, si el valor de DW se acerca a 4, indica autocorrelación negativa en los residuos.
Análisis de residuales bajo el criterio Criterio de Información de Akaike (AIC).#
ei_AIC = model_fit.resid
# Prueba de normalidad de Kolmogorov-Smirnov
ks_result = kstest(ei_AIC, 'norm')
print("Prueba de Kolmogorov-Smirnov: ")
print("Estadístico:", ks_result.statistic)
print("Valor p:", ks_result.pvalue)
Prueba de Kolmogorov-Smirnov:
Estadístico: 0.4846841666313614
Valor p: 0.0
Dado que el P-value \(=0.0 < 0.05\) hay evidencia significativa para rechazar la hipótesis nula con una significancia \(\alpha = 0.05\), es decir que los residuos no siguen una distribución.normal
# Prueba de Durbin-Watson
durbin_watson_statistic = sm.stats.stattools.durbin_watson(ei_AIC)
print("Estadístico de Durbin-Watson:", durbin_watson_statistic)
Estadístico de Durbin-Watson: 2.0205163971116895
Dado que el estadístico de Durbin_Watson \( = 2\), se puede afirmar que no existe una correlacion serial en los residuales.
# Gráficos QQ-plot y Autocorrelación en una sola figura
fig, axs = plt.subplots(1, 2, figsize=(15, 5))
# QQ-plot para los residuales
stats.probplot(ei_AIC, dist="norm", plot=axs[0])
axs[0].get_lines()[0].set_color('#008080') # Establecer el color del gráfico
axs[0].get_lines()[0].set_markersize(2) # Establecer el tamaño de los puntos
axs[0].set_title('QQ-plot para los residuales ordinarios', fontsize=16)
axs[0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axs[0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Autocorrelación de los residuos
sm.graphics.tsa.plot_acf(ei_AIC, lags=40, ax=axs[1], color='#008080', vlines_kwargs={"colors": '#008080'})
axs[1].set_xlabel('Retraso')
axs[1].set_ylabel('Autocorrelación')
axs[1].set_title('Autocorrelación de los residuos', fontsize=16)
axs[1].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axs[1].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Ajustar el espaciado entre los gráficos
plt.tight_layout()
# Mostrar la figura
plt.show()
Basándonos en el gráfico anterior, podemos concluir que, si bien los residuos no siguen estrictamente una distribución normal, sí se observa que cumplen con el supuesto de independencia. Esto se refiere a que los residuos no muestran patrones discernibles en su distribución a lo largo del tiempo, lo que sugiere que están aleatoriamente dispersos. Es importante destacar que este análisis se realiza con un horizonte de 7 días utilizando el criterio AIC.
Gráfica de residuos del modelo ARIMA AIC
Análisis de residuales bajo el criterio Criterio de inferencia Bayesiana (BIC).#
ei_BIC = model_fit_BIC.resid
# Prueba de normalidad de Kolmogorov-Smirnov
ks_result = kstest(ei_BIC, 'norm')
print("Prueba de Kolmogorov-Smirnov: ")
print("Estadístico:", ks_result.statistic)
print("Valor p:", ks_result.pvalue)
Prueba de Kolmogorov-Smirnov:
Estadístico: 0.48216884720896
Valor p: 0.0
Dado que el P-value \(=0.0 < 0.05\) hay evidencia significativa para rechazar la hipótesis nula con una significancia \(\alpha = 0.05\), es decir que los residuos no siguen una distribución.normal
# Prueba de Durbin-Watson
durbin_watson_statistic = sm.stats.stattools.durbin_watson(ei_BIC)
print("Estadístico de Durbin-Watson:", durbin_watson_statistic)
Estadístico de Durbin-Watson: 1.9958621326334947
Dado que el estadístico de Durbin_Watson \( = 2,066\), se puede afirmar que no existe una correlacion serial en los residuales.
# Gráficos QQ-plot y Autocorrelación en una sola figura
fig, axs = plt.subplots(1, 2, figsize=(15, 5))
# QQ-plot para los residuales
stats.probplot(ei_BIC, dist="norm", plot=axs[0])
axs[0].get_lines()[0].set_color('#008080') # Establecer el color del gráfico
axs[0].get_lines()[0].set_markersize(2) # Establecer el tamaño de los puntos
axs[0].set_title('QQ-plot para los residuales ordinarios', fontsize=16)
axs[0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axs[0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Autocorrelación de los residuos
sm.graphics.tsa.plot_acf(ei_BIC, lags=40, ax=axs[1], color='#008080', vlines_kwargs={"colors": '#008080'})
axs[1].set_xlabel('Retraso')
axs[1].set_ylabel('Autocorrelación')
axs[1].set_title('Autocorrelación de los residuos', fontsize=16)
axs[1].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axs[1].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Ajustar el espaciado entre los gráficos
plt.tight_layout()
# Mostrar la figura
plt.show()
Basándonos en el gráfico anterior, podemos concluir que, si bien los residuos no siguen estrictamente una distribución normal, sí se observa que cumplen con el supuesto de independencia. Esto se refiere a que los residuos no muestran patrones discernibles en su distribución a lo largo del tiempo, lo que sugiere que están aleatoriamente dispersos. Es importante destacar que este análisis se realiza con un horizonte de 7 días utilizando el criterio BIC.
Análisis de residuales bajo el Criterio de información de Hannan-Quinn (HQIC).#
ei_HQIC = model_fit_HQIC.resid
# Prueba de normalidad de Kolmogorov-Smirnov
ks_result = kstest(ei_HQIC, 'norm')
print("Prueba de Kolmogorov-Smirnov: ")
print("Estadístico:", ks_result.statistic)
print("Valor p:", ks_result.pvalue)
Prueba de Kolmogorov-Smirnov:
Estadístico: 0.4846841666313614
Valor p: 0.0
Dado que el P-value \(=0.0 < 0.05\) hay evidencia significativa para rechazar la hipótesis nula con una significancia \(\alpha = 0.05\), es decir que los residuos no siguen una distribución.normal
# Prueba de Durbin-Watson
durbin_watson_statistic = sm.stats.stattools.durbin_watson(ei_HQIC)
print("Estadístico de Durbin-Watson:", durbin_watson_statistic)
Estadístico de Durbin-Watson: 2.0205163971116895
Dado que el estadístico de Durbin_Watson \( = 2,066\), se puede afirmar que no existe una correlacion serial en los residuales.
# Gráficos QQ-plot y Autocorrelación en una sola figura
fig, axs = plt.subplots(1, 2, figsize=(15, 5))
# QQ-plot para los residuales
stats.probplot(ei_HQIC, dist="norm", plot=axs[0])
axs[0].get_lines()[0].set_color('#008080') # Establecer el color del gráfico
axs[0].get_lines()[0].set_markersize(2) # Establecer el tamaño de los puntos
axs[0].set_title('QQ-plot para los residuales ordinarios', fontsize=16)
axs[0].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axs[0].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Autocorrelación de los residuos
sm.graphics.tsa.plot_acf(ei_HQIC, lags=40, ax=axs[1], color='#008080', vlines_kwargs={"colors": '#008080'})
axs[1].set_xlabel('Retraso')
axs[1].set_ylabel('Autocorrelación')
axs[1].set_title('Autocorrelación de los residuos', fontsize=16)
axs[1].tick_params(axis='x', labelsize=10) # Solo para el eje x (inferior)
axs[1].tick_params(axis='y', labelsize=10) # Solo para el eje y (izquierdo)
# Ajustar el espaciado entre los gráficos
plt.tight_layout()
# Mostrar la figura
plt.show()
Basándonos en el gráfico anterior, podemos concluir que, si bien los residuos no siguen estrictamente una distribución normal, sí se observa que cumplen con el supuesto de independencia. Esto se refiere a que los residuos no muestran patrones discernibles en su distribución a lo largo del tiempo, lo que sugiere que están aleatoriamente dispersos. Es importante destacar que este análisis se realiza con un horizonte de 7 días utilizando el criterio HQIC.
Comparación de modelos ARIMA basada en los criterios utilizados para su construcción#
A continuación se presenta el resultado obtenido para los tres criterios utilizados en este informe para construir nuestro mejor modelo ARIMA:
dftotal = pd.concat([fraic7, fraic14, fraic21, fraic28, faic7, faic14, faic21, faic28, frbic7, frbic14, frbic21, frbic28, fbic7, fbic14, fbic21, fbic28, frhqic7, frhqic14, frhqic21, frhqic28, fhqic7, fhqic14, fhqic21, fhqic28 ], axis=0)
dftotalr = dftotal.round(3)
print(dftotalr)
MAPE MAE RMSE MSE R2
AIC usando Rolling 7 días 0.021 1394.548 1797.175 3.229839e+06 0.559
AIC usando Rolling 14 días 0.022 1512.959 1967.627 3.871557e+06 0.335
AIC usando Rolling 21 días 0.021 1411.730 1810.354 3.277380e+06 0.309
AIC usando Rolling 28 días 0.024 1599.699 1957.321 3.831107e+06 0.537
AIC sin Rolling7 días 0.048 3281.089 3606.585 1.300746e+07 -0.776
AIC sin Rolling 14 días 0.046 3219.495 3668.064 1.345470e+07 -1.311
AIC sin Rolling 21 días 0.051 3528.430 3891.219 1.514158e+07 -2.194
AIC sin Rolling 28 días 0.046 3126.999 3546.356 1.257664e+07 -0.521
BIC usando Rolling 7 días 0.032 2139.501 3118.216 9.723271e+06 -0.328
BIC usando Rolling 14 días 0.026 1730.585 2283.684 5.215211e+06 0.104
BIC usando Rolling 21 días 0.024 1641.197 2247.055 5.049256e+06 -0.065
BIC usando Rolling 28 días 0.023 1574.952 1951.188 3.807135e+06 0.540
BIC sin Rolling 7 días 0.047 3245.578 3539.053 1.252490e+07 -0.710
BIC sin Rolling 14 días 0.046 3163.644 3589.860 1.288710e+07 -1.213
BIC sin Rolling 21 días 0.050 3454.462 3802.383 1.445812e+07 -2.050
BIC sin Rolling 28 días 0.045 3083.276 3484.664 1.214288e+07 -0.469
HQIC usando Rolling 7 días 0.034 2251.210 3204.519 1.026894e+07 -0.402
HQIC usando Rolling 14 días 0.025 1701.208 2237.010 5.004214e+06 0.141
HQIC usando Rolling 21 días 0.024 1611.084 2130.011 4.536948e+06 0.043
HQIC usando Rolling 28 días 0.023 1558.230 1926.854 3.712766e+06 0.551
HQIC sin Rolling 7 días 0.048 3281.089 3606.585 1.300746e+07 -0.776
HQIC sin Rolling 14 días 0.046 3219.495 3668.064 1.345470e+07 -1.311
HQIC sin Rolling 21 días 0.051 3528.430 3891.219 1.514158e+07 -2.194
HQIC sin Rolling 28 días 0.046 3126.999 3546.356 1.257664e+07 -0.521
AIC (Akaike Information Criterion):El modelo AIC tiende a tener MAPE, RMSE y MSE más bajos que BIC y HQIC en todos los horizontes de tiempo, lo que indica una mejor precisión en las predicciones.Además, el modelo AIC muestra valores de R2 más altos en comparación con BIC y HQIC en la mayoría de los horizontes de tiempo, indicando una mejor capacidad para explicar la variabilidad en los datos.
BIC (Bayesian Information Criterion):Aunque BIC muestra valores relativamente más altos en MAPE, MAE y RMSE en comparación con AIC, sigue siendo competitivo en términos de precisión de predicción en algunos horizontes de tiempo. Además, el modelo BIC muestra valores de R2 mixtos, pero en general, son menores que los del modelo AIC.
HQIC (Hannan-Quinn Information Criterion):El modelo HQIC muestra resultados similares a BIC en términos de precisión de predicción, con MAPE, MAE y RMSE ligeramente más altos que AIC en la mayoría de los casos. Además, Los valores de R2 de HQIC son comparables con los de BIC y en algunos casos ligeramente más bajos. En general, HQIC no parece superar consistentemente a AIC o BIC.
En términos generales, el modelo AIC parece ser la mejor opción, ya que tiende a tener la mejor precisión en la mayoría de las métricas y una capacidad razonable para explicar la variabilidad en los datos.
Conclusión:#
En términos generales, basándonos en los resultados derivados de este estudio, podemos afirmar que el modelo ARIMA que exhibe un mejor ajuste a las predicciones de nuestra serie temporal es el modelo ARIMA seleccionado a través del criterio de Información de Akaike (AIC), particularmente en las ventanas de horizonte de 7 y 28 días. Este modelo ha demostrado ser el más idóneo para capturar la complejidad inherente de la serie temporal, logrando explicar el 55.9% y el 53.9% de la variabilidad de los datos, respectivamente. En comparación con los criterios de Inferencia Bayesiana (BIC) e Información de Hannan-Quinn (HQIC), este modelo exhibe una superioridad notable al producir predicciones precisas y confiables para los datos predichos.